I want to add a Build step with the Groovy plugin to read a file and trigger a build fail depending on the content of the file.
How can I inject the workspace file path in the groovy plugin ?
myFileDirectory = // Get workspace filepath here ???
myFileName = "output.log"
myFile = new File(myFileDirectory + myFileName)
lastLine = myFile.readLines().get(myFile.readLines().size().toInteger() - 1)
if (lastLine ==~ /.Fatal Error.*/ ){
println "Fatal error found"
System.exit(1)
} else{
println "nothing to see here"
}
I realize this question was about creating a plugin, but since the new Jenkins 2 Pipeline builds use Groovy, I found myself here while trying to figure out how to read a file from a workspace in a Pipeline build. So maybe I can help someone like me out in the future.
Turns out it's very easy, there is a readfile step, and I should have rtfm:
env.WORKSPACE = pwd()
def version = readFile "${env.WORKSPACE}/version.txt"
If you are trying to read a file from the workspace during a pipeline build step, there's a method for that:
readFile('name-of-file.groovy')
For reference, see https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#readfile-read-file-from-workspace.
Based on your comments, you would be better off with Text-finder plugin.
It allows to search file(s), as well as console, for a regular expression and then set the build either unstable or failed if found.
As for the Groovy, you can use the following to access ${WORKSPACE} environment variable:
def workspace = manager.build.getEnvVars()["WORKSPACE"]
Although this question is only related to finding directory path ($WORKSPACE) however I had a requirement to read the file from workspace and parse it into JSON object to read sonar issues ( ignore minor/notes issues )
Might help someone, this is how I did it-
from readFile
jsonParse(readFile('xyz.json'))
and jsonParse method-
#NonCPS
def jsonParse(text) {
return new groovy.json.JsonSlurperClassic().parseText(text);
}
This will also require script approval in ManageJenkins-> In-process script approval
May this help to someone if they have the same requirement.
This will read a file that contains the Jenkins Job name and run them iteratively from one single job.
Please change below code accordingly in your Jenkins.
pipeline {
agent any
stages {
stage('Hello') {
steps {
script{
git branch: 'Your Branch name', credentialsId: 'Your crendiatails', url: ' Your BitBucket Repo URL '
##To read file from workspace which will contain the Jenkins Job Name ###
def filePath = readFile "${WORKSPACE}/ Your File Location"
##To read file line by line ###
def lines = filePath.readLines()
##To iterate and run Jenkins Jobs one by one ####
for (line in lines) {
build(job: "$line/branchName",
parameters:
[string(name: 'vertical', value: "${params.vert}"),
string(name: 'environment', value: "${params.env}"),
string(name: 'branch', value: "${params.branch}"),
string(name: 'project', value: "${params.project}")
]
)
}
}
}
}
}
}
If you already have the Groovy (Postbuild) plugin installed, I think it's a valid desire to get this done with (generic) Groovy instead of installing a (specialized) plugin.
That said, you can get the workspace using manager.build.workspace.getRemote(). Don't forget to add File.separator between path and file name.
As mentioned in a different post Read .txt file from workspace groovy script in Jenkins I was struggling to make it work for the pom modules for a file in the workspace, in the
Extended Choice Parameter. Here is my solution with the printlns:
import groovy.util.XmlSlurper
import java.util.Map
import jenkins.*
import jenkins.model.*
import hudson.*
import hudson.model.*
try{
//get Jenkins instance
def jenkins = Jenkins.instance
//get job Item
def item = jenkins.getItemByFullName("The_JOB_NAME")
println item
// get workspacePath for the job Item
def workspacePath = jenkins.getWorkspaceFor (item)
println workspacePath
def file = new File(workspacePath.toString()+"\\pom.xml")
def pomFile = new XmlSlurper().parse(file)
def pomModules = pomFile.modules.children().join(",")
return pomModules
} catch (Exception ex){
println ex.message
}
Related
my task is to collect node details and list them in certail format. I need to write data to a file and save it as csv file and attach it as artifacts.
But i am not able to create a file using groovy scripts in the jenkins using plugin "Execute System Groovy" as build step
import jenkins.model.Jenkins
import hudson.model.User
import hudson.security.Permission
import hudson.EnvVars
EnvVars envVars = build.getEnvironment(listener);
filename = envVars.get('WORKSPACE') + "\\node_details.txt";
//filename = "${manager.build.workspace.remote}" + "\\node_details.txt"
targetFile = new File(filename);
println "attempting to create file: $targetFile"
if (targetFile.createNewFile()) {
println "Successfully created file $targetFile"
} else {
println "Failed to create file $targetFile"
}
print "Deleting ${targetFile.getAbsolutePath()} : "
println targetFile.delete()
Output obtained
attempting to create file: /home/jenkins/server-name/workspace/GET_NODE_DETAILS\node_details.txt
FATAL: No such file or directory
java.io.IOException: No such file or directory
at java.io.UnixFileSystem.createFileExclusively(Native Method)
at java.io.File.createNewFile(File.java:947)
at java_io_File$createNewFile.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
at Script1.run(Script1.groovy:13)
at groovy.lang.GroovyShell.evaluate(GroovyShell.java:682)
at groovy.lang.GroovyShell.evaluate(GroovyShell.java:666)
at hudson.plugins.groovy.SystemGroovy.perform(SystemGroovy.java:81)
at hudson.tasks.BuildStepMonitor$1.perform(BuildStepMonitor.java:20)
at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:772)
at hudson.model.Build$BuildExecution.build(Build.java:199)
at hudson.model.Build$BuildExecution.doRun(Build.java:160)
at hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:535)
at hudson.model.Run.execute(Run.java:1732)
at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:43)
at hudson.model.ResourceController.execute(ResourceController.java:88)
at hudson.model.Executor.run(Executor.java:234)
Some time i see people use "manager" object, how can i get access to it ?
Alos any ideas on how to accomplish the task ?
Problem
Groovy system script is always run in jenkins master node, while the workspace is the file path in your jenkins slave node, which doesn't exist in your master node.
You can verify by the code
theDir = new File(envVars.get('WORKSPACE'))
println theDir.exists()
It will return false
If you don't use slave node, it will return true
Solution As we can't use normal File, we have to use FilePath http://javadoc.jenkins-ci.org/hudson/FilePath.html
if(build.workspace.isRemote())
{
channel = build.workspace.channel;
fp = new FilePath(channel, build.workspace.toString() + "/node_details.txt")
} else {
fp = new FilePath(new File(build.workspace.toString() + "/node_details.txt"))
}
if(fp != null)
{
fp.write("test data", null); //writing to file
}
Then it works in both case.
Answer by #Larry Cai covers one part to write a file to slave node from System Groovy Script (as it runs on Master Node).
The part I am answering is "Some time i see people use "manager" object, how can i get access to it "
This is the object already available in Post Build Groovy Script for accessing a lot of things like environment variables, Build Status, Build Display Name etc.
Quoted from https://wiki.jenkins-ci.org/display/JENKINS/Groovy+Postbuild+Plugin :
"The groovy script can use the variable manager, which provides various methods to decorate your builds.
Those methods can be classified into whitelisted methods and non-whitelisted methods."
To access it, we can directly call it in the post build groovy script. e.g
manager.build.setDescription("custom description")
manager.addShortText("add your message here")
All methods available on manager objects are documented here.
https://wiki.jenkins-ci.org/display/JENKINS/Groovy+Postbuild+Plugin#GroovyPostbuildPlugin-Whitelistedmethods
I suspect the error was caused by the path format, could you try below:
change
filename = envVars.get('WORKSPACE') + "\\node_details.txt";
to
filename = envVars.get('WORKSPACE') + "/node_details.txt";
Because when I tried in my local jenkins server, I get it successfully executed.
The manager object is not available depending on how the groovy is invoked. e.g. in "execute system groovy script".
You can find the BadgeManager class in jenkins GroovyPostBuild plugin API here: https://javadoc.jenkins.io/plugin/groovy-postbuild/org/jvnet/hudson/plugins/groovypostbuild/GroovyPostbuildRecorder.BadgeManager.html#addShortText-java.lang.String-
ANSWER: Import the GroovyPostBuild plugin and create a new manager object. e.g. here a job with "Execute System Groovy Script" create a manager object and call the addShortText method:
// java.lang.Object
// org.jvnet.hudson.plugins.groovypostbuild.GroovyPostbuildRecorder.BadgeManager
// Constructor and Description
// BadgeManager(hudson.model.Run<?,?> build, hudson.model.TaskListener listener, hudson.model.Result scriptFailureResult)
import hudson.model.*
import org.jvnet.hudson.plugins.groovypostbuild.GroovyPostbuildAction
def build = Thread.currentThread().executable
manager = new org.jvnet.hudson.plugins.groovypostbuild.GroovyPostbuildRecorder.BadgeManager(build, null, null)
manager.addShortText("MANAGER TEST", "black", "limegreen", "0px", "white")
This question gives a hint: See here for a nearly working answer:
In jenkins job, create file using system groovy in current workspace
org.jvnet.hudson.plugins.groovypostbuild.GroovyPostbuildAction and build.getActions().add(GroovyPostbuildAction.createShortText(text, "black", "limegreen", "0px", "white"));
I have a multi-configuration build for which I'd like essentally one build to be run for each file matching foo/*/bar/*.xml. I figured the GroovyAxis Plugin would be a nice fit, but I cannot find any documentation on how the build configuration can be accessed from within the script, so I cannot read the workspace-directory from anywhere.
Running something like return new File('.').listFiles().collect{it.toString()} returns all files within the root directory of the server.
Can anyone point me in the right direction?
It took a while to figure this out, but here is a solution. Note that since the Groovy script runs on the master, you must use FilePath to access the files on the slave.
import hudson.FilePath
def workspace = context?.build?.workspace
if (null == workspace) {
return ['noworkspace'] // avoid returning 'default' so the user has a chance of figuring out what went wrong
}
def configDir = workspace.toString() + '/openpower/configs/'
def dir = new FilePath(workspace.channel, configDir)
def files = []
dir.list().each {
def name = it.getName()
if (name.endsWith('_defconfig')) {
files << name.replace('_defconfig', '')
}
}
return files
What I've Done
I am using soapUI (3.6.1 Free version) mock services to serve up specific data to 2 client applications I am testing. With some simple Groovy script I've set up some mock operations to fetch responses from specific files based on the requests made by the client applications.
The static contents of the mock response is:
${responsefile}
The groovy in the operation dispatch scripting pane is:
def req = new XmlSlurper().parseText(mockRequest.requestContent)
if (req =~ "CategoryA")
{
context.responsefile = new File("C:/soapProject/Test_Files/ID_List_CategoryA.xml").text
}
else
{
context.responsefile = new File("C:/soapProject/Test_Files/ID_List_CategoryB.xml").text
}
In this example, when the client application issues a request to the mock service that contains the string CategoryA, the response returned by soapUI is the contents of file ID_List_CategoryA.xml
What I'm Trying To Achieve
This all works fine with the absolute paths in the groovy. Now I want to pull the whole collection of soapUI project file and external files into a package for easy re-deployment. From my reading about soapUI I hoped this would be as easy as setting the project Resource Root value to ${projectDir} and changing my paths to:
def req = new XmlSlurper().parseText(mockRequest.requestContent)
if (req =~ "CategoryA")
{
context.responsefile = new File("Test_Files/ID_List_CategoryA.xml").text
}
else
{
context.responsefile = new File("Test_Files/ID_List_CategoryB.xml").text
}
... keeping in mind that the soapUI project xml file resides in C:/soapProject/
What I've Tried So Far
So, that doesn't work. I've tried variations of relative paths:
./Test_Files/ID_List_CategoryA.xml
/Test_Files/ID_List_CategoryA.xml
Test_Files/ID_List_CategoryA.xml
One post indicated that soapUI might consider the project files parent directory as the root for the purposes of the relative path, so tried the following variations too:
./soapProject/Test_Files/ID_List_CategoryA.xml
/soapProject/Test_Files/ID_List_CategoryA.xml
soapProject/Test_Files/ID_List_CategoryA.xml
When none of that worked I tried making use of the ${projectDir} property in the groovy script, but all such attempts failed with a "No such property: mockService for class: Script[n]" error. Admittefly, I was really fumbling around when trying to do that.
I tried using information from this post and others: How do I make soapUI attachment paths relative?
... without any luck. Replacing "test" with "mock," (among other changes), in the solution code from that post resulted in more property errors, e.g.
testFile = new File(mockRunner.project.getPath())
.. led to...
No such property: mockRunner for class: Script3
What I Think I Need
The posts I've found related to this issue all focus on soapUI TestSuites. I really need a solution that is MockService centric or at least sheds some light on how it can be handled differently for MockServices as opposed to TestSuites.
Any help is greatly appreciated. Thanks. Mark.
The Solution - Provided by GargantuChet
The following includes the changes suggested by GargantuChet to solve the problem of trying to access the ${projectDir} property and enable the use of relative paths by defining a new projectDir object within the scope of the groovy script:
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
def projectDir = groovyUtils.projectPath
def req = new XmlSlurper().parseText(mockRequest.requestContent)
if (req =~ "CategoryA")
{
context.responsefile = new File(projectDir, "Test_Files/ID_List_CategoryA.xml").text
}
else
{
context.responsefile = new File(projectDir, "Test_Files/ID_List_CategoryB.xml").text
}
I'm not familiar with Groovy, but I assume the File is a normal java.io.File instance.
Relative paths are interpreted as being relative to the application's current directory. Try something like the following to verify:
def defaultPathBase = new File( "." ).getCanonicalPath()
println "Current dir:" + defaultPathBase
If this is the case here, then you may want to use the new File(String parent, String child) constructor, passing your resource directory as the first argument and the relative path as the second.
For example:
// hardcoded for demonstration purposes
def pathbase = "/Users/chet"
def content = new File(pathbase, "Desktop/sample.txt").text
println content
Here's the result of executing the script:
Chets-MacBook-Pro:Desktop chet$ groovy sample.groovy
This is a sample text file.
It will be displayed by a Groovy script.
Chets-MacBook-Pro:Desktop chet$ groovy sample.groovy
This is a sample text file.
It will be displayed by a Groovy script.
Chets-MacBook-Pro:Desktop chet$
You could have also done the following to get the value of projectDir:
def projectDir = context.expand('${projectDir}');
I have a parameterized job that uses the Perforce plugin and would like to retrieve the build parameters/properties as well as the p4.change property that's set by the Perforce plugin.
How do I retrieve these properties with the Jenkins Groovy API?
Update: Jenkins 2.x solution:
With Jenkins 2 pipeline dsl, you can directly access any parameter with the trivial syntax based on the params (Map) built-in:
echo " FOOBAR value: ${params.'FOOBAR'}"
The returned value will be a String or a boolean depending on the Parameter type itself. The syntax is the same for scripted or declarative syntax. More info at: https://jenkins.io/doc/book/pipeline/jenkinsfile/#handling-parameters
If your parameter name is itself in a variable:
def paramName = "FOOBAR"
def paramValue = params.get(paramName) // or: params."${paramName}"
echo """ FOOBAR value: ${paramValue}"
Original Answer for Jenkins 1.x:
For Jenkins 1.x, the syntax is based on the build.buildVariableResolver built-ins:
// ... or if you want the parameter by name ...
def hardcoded_param = "FOOBAR"
def resolver = build.buildVariableResolver
def hardcoded_param_value = resolver.resolve(hardcoded_param)
Please note the official Jenkins Wiki page covers this in more details as well, especially how to iterate upon the build parameters:
https://wiki.jenkins-ci.org/display/JENKINS/Parameterized+System+Groovy+script
The salient part is reproduced below:
// get parameters
def parameters = build?.actions.find{ it instanceof ParametersAction }?.parameters
parameters.each {
println "parameter ${it.name}:"
println it.dump()
}
For resolving a single parameter (I guess what's most commonly needed), this is the simplest I found:
build.buildVariableResolver.resolve("myparameter")
in your Groovy System script build step.
Regarding parameters:
See this answer first. To get a list of all the builds for a project (obtained as per that answer):
project.builds
When you find your particular build, you need to get all actions of type ParametersAction with build.getActions(hudson.model.ParametersAction). You then query the returned object for your specific parameters.
Regarding p4.change: I suspect that it is also stored as an action. In Jenkins Groovy console get all actions for a build that contains p4.change and examine them - it will give you an idea what to look for in your code.
I've just got this working, so specifically, using the Groovy Postbuild plugin, you can do the following:
def paramText
def actionList = manager.build.getActions(hudson.model.ParametersAction)
if (actionList.size() != 0)
{
def pA = actionList.get(0)
paramText = pA.createVariableResolver(manager.build).resolve("MY_PARAM_NAME")
}
In cases when a parameter name cannot be hardcoded I found this would be the simplest and best way to access parameters:
def myParam = env.getProperty(dynamicParamName)
In cases, when a parameter name is known and can be hardcoded the following 3 lines are equivalent:
def myParam = env.getProperty("myParamName")
def myParam = env.myParamName
def myParam = myParamName
To get the parameterized build params from the current build from your GroovyScript (using Pipeline), all you need to do is:
Say you had a variable called VARNAME.
def myVariable = env.VARNAME
Get all of the parameters:
System.getenv().each{
println it
}
Or more sophisticated:
def myvariables = getBinding().getVariables()
for (v in myvariables) {
echo "${v} " + myvariables.get(v)
}
You will need to disable "Use Groovy Sandbox" for both.
If you are trying to get all parameters passed to Jenkins job you can use the global variable params in your groovy pipeline to fetch it.
http://jenkins_host:8080/pipeline-syntax/globals
params
Use something like below.
def dumpParameter()
{
params.each {
println it.key + " = " + it.value
}
}
thanks patrice-n! this code worked to get both queued and running jobs and their parameters:
import hudson.model.Job
import hudson.model.ParametersAction
import hudson.model.Queue
import jenkins.model.Jenkins
println("================================================")
for (Job job : Jenkins.instanceOrNull.getAllItems(Job.class)) {
if (job.isInQueue()) {
println("------------------------------------------------")
println("InQueue " + job.name)
Queue.Item queue = job.getQueueItem()
if (queue != null) {
println(queue.params)
}
}
if (job.isBuilding()) {
println("------------------------------------------------")
println("Building " + job.name)
def build = job.getBuilds().getLastBuild()
def parameters = build?.getAllActions().find{ it instanceof ParametersAction }?.parameters
parameters.each {
def dump = it.dump()
println "parameter ${it.name}: ${dump}"
}
}
}
println("================================================")
The following can be used to retreive an environment parameter:
println System.getenv("MY_PARAM")
The following snippet worked for me to get a parameter value in a parameterized project:
String myParameter = this.getProperty('binding').getVariable('MY_PARAMETER')
The goal was to dynamically lock a resource based on the selected project parameter.
In "[✓] This build requires lockable resources" I have the following "[✓] Groovy Expression":
if (resourceName == 'resource_lock_name') {
Binding binding = this.getProperty('binding')
String profile = binding.getVariable('BUILD_PROFILE')
return profile == '-Poradb' // acquire lock if "oradb" profile is selected
}
return false
In "[✓] This project is parameterized" section I have a "Choice Parameter" named e.g. BUILD_PROFILE
Example of Choices are:
-Poradb
-Ph2db
-DskipTests -T4
The lock on "resource_lock_name" will be acquired only if "-Poradb" is selected when building project with parameters
[-] Use Groovy Sandbox shall be unchecked for this syntax to work
My project takes in a version number (separated by '.' or '_'). I tried writing a Groovy script that creates a Jenkins environment variable using only the first two of these numbers:
//Get the version parameter
def env = System.getenv()
def version = env['currentversion']
def m = version =~/\d{1,2}/
env = ['miniVersion':m[0].m[1]]
Am I doing this correctly? Can I even create a new environment variable? Is there a better solution to this?
Jenkins 1.x
The following groovy snippet should pass the version (as you've already supplied), and store it in the job's variables as 'miniVersion'.
import hudson.model.*
def env = System.getenv()
def version = env['currentversion']
def m = version =~/\d{1,2}/
def minVerVal = m[0]+"."+m[1]
def pa = new ParametersAction([
new StringParameterValue("miniVersion", minVerVal)
])
// add variable to current job
Thread.currentThread().executable.addAction(pa)
The variable will then be accessible from other build steps. e.g.
echo miniVersion=%miniVersion%
Outputs:
miniVersion=12.34
I believe you'll need to use the "System Groovy Script" (on the Master node only) as opposed to the "Groovy Plugin" - https://wiki.jenkins-ci.org/display/JENKINS/Groovy+plugin#Groovyplugin-GroovyScriptvsSystemGroovyScript
Jenkins 2.x
I believe the previous (Jenkins 1.x) behaviour stopped working because of this Security Advisory...
Solution (paraphrased from the Security Advisory)
It's possible to restore the previous behaviour by setting the system property hudson.model.ParametersAction.keepUndefinedParameters to true. This is potentially very unsafe and intended as a short-term workaround only.
java -Dhudson.model.ParametersAction.keepUndefinedParameters=true -jar jenkins.war
To allow specific, known safe parameter names to be passed to builds, set the system property hudson.model.ParametersAction.safeParameters to a comma-separated list of safe parameter names.
e.g.
java -Dhudson.model.ParametersAction.safeParameters=miniVersion,FOO,BAR -jar jenkins.war
And in groovy these two lines should be written this way:
System.setProperty("hudson.model.ParametersAction.keepUndefinedParameters","true");
System.setProperty("hudson.model.ParametersAction.safeParameters","miniVersion,FOO,BAR");
You can also define a variable without the EnvInject Plugin within your Groovy System Script:
import hudson.model.*
def build = Thread.currentThread().executable
def pa = new ParametersAction([
new StringParameterValue("FOO", "BAR")
])
build.addAction(pa)
Then you can access this variable in the next build step which (for example) is an windows batch command:
#echo off
Setlocal EnableDelayedExpansion
echo FOO=!FOO!
This echo will show you "FOO=BAR".
Regards
For me, the following also worked in Jenkins 2 (2.73.3)
Replace
def pa = new ParametersAction([new StringParameterValue("FOO", foo)])
build.addAction(pa)
with
def pa = new ParametersAction([new StringParameterValue("FOO", foo)], ["FOO"])
build.addAction(pa)
ParametersAction seems to have a second constructor which allows to pass in "additionalSafeParameters" https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/hudson/model/ParametersAction.java
As other answers state setting new ParametersAction is the way to inject one or more environment variables, but when a job is already parameterised adding new action won't take effect. Instead you'll see two links to a build parameters pointing to the same set of parameters and the one you wanted to add will be null.
Here is a snippet updating the parameters list in both cases (a parametrised and non-parametrised job):
import hudson.model.*
def build = Thread.currentThread().executable
def env = System.getenv()
def version = env['currentversion']
def m = version =~/\d{1,2}/
def minVerVal = m[0]+"."+m[1]
def newParams = null
def pl = new ArrayList<StringParameterValue>()
pl.add(new StringParameterValue('miniVersion', miniVerVal))
def oldParams = build.getAction(ParametersAction.class)
if(oldParams != null) {
newParams = oldParams.createUpdated(pl)
build.actions.remove(oldParams)
} else {
newParams = new ParametersAction(pl)
}
build.addAction(newParams)
The Jenkins EnvInject Plugin might be able to help you. It allows injecting environment variables into the build environment.
I know it has some ability to do scripting, so it might be able to do what you want. I have only used it to set simple properties (e.g. "LOG_PATH=${WORKSPACE}\logs").
After searching around a bit, the best solution in my opinion makes use of hudson.model.EnvironmentContributingAction.
import hudson.model.EnvironmentContributingAction
import hudson.model.AbstractBuild
import hudson.EnvVars
class BuildVariableInjector {
def build
def out
def BuildVariableInjector(build, out) {
this.build = build
this.out = out
}
def addBuildEnvironmentVariable(key, value) {
def action = new VariableInjectionAction(key, value)
build.addAction(action)
//Must call this for action to be added
build.getEnvironment()
}
class VariableInjectionAction implements EnvironmentContributingAction {
private String key
private String value
public VariableInjectionAction(String key, String value) {
this.key = key
this.value = value
}
public void buildEnvVars(AbstractBuild build, EnvVars envVars) {
if (envVars != null && key != null && value != null) {
envVars.put(key, value);
}
}
public String getDisplayName() {
return "VariableInjectionAction";
}
public String getIconFileName() {
return null;
}
public String getUrlName() {
return null;
}
}
}
I use this class in a system groovy script (using the groovy plugin) within a job.
import hudson.model.*
import java.io.File;
import jenkins.model.Jenkins;
def jenkinsRootDir = build.getEnvVars()["JENKINS_HOME"];
def parent = getClass().getClassLoader()
def loader = new GroovyClassLoader(parent)
def buildVariableInjector = loader.parseClass(new File(jenkinsRootDir + "/userContent/GroovyScripts/BuildVariableInjector.groovy")).newInstance(build, getBinding().out)
def projectBranchDependencies = []
//Some logic to set projectBranchDependencies variable
buildVariableInjector.addBuildEnvironmentVariable("projectBranchDependencies", projectBranchDependencies.join(","));
You can then access the projectBranchDependencies variable at any other point in your build, in my case, from an ANT script.
Note: I borrowed / modified the ideas for parts of this implementation from a blog post, but at the time of this posting I was unable to locate the original source in order to give due credit.
Just had the same issue. Wanted to dynamically trigger parametrized downstream jobs based on the outcome of some groovy scripting.
Unfortunately on our Jenkins it's not possible to run System Groovy scripts. Therefore I had to do a small workaround:
Run groovy script which creates a properties file where the environment variable to be set is specified
def props = new File("properties.text")
if (props.text == 'foo=bar') {
props.text = 'foo=baz'
} else {
props.text = 'foo=bar'
}
Use env inject plugin to inject the variable written into this script
Inject environment variable
Property file path: properties.text
After that I was able to use the variable 'foo' as parameter for the parametrized trigger plugin. Some kind of workaround. But works!
My environment was prior tooling such as Jenkins and was running with batch files (I know, I'm old). So those batch files (and their sub-batch files) are using environment variables. This was my piece of groovy script which injects environment variables. The names and parameters used are dummy ones.
// The process/batch which uses environment variables
def buildLabel = "SomeVersionNr"
def script = "startBuild.bat"
def processBuilder = new ProcessBuilder(script, buildLabel)
//Inject our environment variables
Map<String, String> env = processBuilder.environment()
env.put("ProjectRoot", "someLocation")
env.put("SomeVar", "Some")
Process p = processBuilder.start()
p.waitFor()
Of course if you set Jenkins up from scratch you would probably do it differently and share the variables in another way, or pass parameters around but this might come handy.
On my side it only worked this way by replacing an existing parameter.
def artifactNameParam = new StringParameterValue('CopyProjectArtifactName', 'bla bla bla')
build.replaceAction(new ParametersAction(artifactNameParam))
Additionally this script must be run with system groovy.
A groovy must be manually installed on that system and the bin dir of groovy must be added to path. Additionally in the lib folder I had to add jenkins-core.jar.
Then it was possible to modify a parameter in a groovy script and get the modified value in a batch script after to continue work.
For me the following worked on Jenkins 2.190.1 and was much simpler than some of the other workarounds:
matcher = manager.getLogMatcher('^.*Text we want comes next: (.*)$');
if (matcher.matches()) {
def myVar = matcher.group(1);
def envVar = new EnvVars([MY_ENV_VAR: myVar]);
def newEnv = Environment.create(envVar);
manager.build.environments.add(0, newEnv);
// now the matched text from the LogMatcher is passed to an
// env var we can access at $MY_ENV_VAR in post build steps
}
This was using the Groovy Script plugin with no additional changes to Jenkins.
You can also create a global environment variable for jenkins if want to use wider.
Written here longer.
import hudson.EnvVars;
import hudson.slaves.EnvironmentVariablesNodeProperty;
import hudson.slaves.NodeProperty;
import hudson.slaves.NodePropertyDescriptor;
import hudson.util.DescribableList;
import jenkins.model.Jenkins;
public createGlobalEnvironmentVariables(String key, String value){
Jenkins instance = Jenkins.getInstance();
DescribableList<NodeProperty<?>, NodePropertyDescriptor> globalNodeProperties = instance.getGlobalNodeProperties();
List<EnvironmentVariablesNodeProperty> envVarsNodePropertyList = globalNodeProperties.getAll(EnvironmentVariablesNodeProperty.class);
EnvironmentVariablesNodeProperty newEnvVarsNodeProperty = null;
EnvVars envVars = null;
if ( envVarsNodePropertyList == null || envVarsNodePropertyList.size() == 0 ) {
newEnvVarsNodeProperty = new hudson.slaves.EnvironmentVariablesNodeProperty();
globalNodeProperties.add(newEnvVarsNodeProperty);
envVars = newEnvVarsNodeProperty.getEnvVars();
} else {
envVars = envVarsNodePropertyList.get(0).getEnvVars();
}
envVars.put(key, value)
instance.save()
}
createGlobalEnvironmentVariables('Var1','Dummy')