34

I have a Maven job in Jenkins. Before the actual build step I have an "Execute shell" pre-build step. In that shell I set a variable:

REVISION=$(cat .build_revision)

I would like to use that variable in the Maven build job in "Goals and options":

clean install -Drevision=${REVISION}

But that does not work! The "Drevision" is set to "${REVISION}" not the actual value of ${REVISION}. Output:

Executing Maven:  -B -f /home/gerrit/.jenkins/jobs/<job_name>/workspace/pom.xml clean install -Drevision=${REVISION}

It works with Jenkins environment variables:

clean install -Dbuild=${BUILD_NUMBER}

It sets "Dbuild" to the actual build number. Output:

Executing Maven:  -B -f /home/gerrit/.jenkins/jobs/<job_name>/workspace/pom.xml clean install -Dbuild=54

My question: How to use a shell variable in Maven "Goals and options"??

EDIT:

I tried using Jenkins EnvInject Plugin to "Inject environment variables" after the pre-build shell, and my variable is now accessible by e.g. post-build shells, but it is still not available in Maven "Goals and options".

Then it is possible to set "Inject environment variables to the build process" using the EnvInject Plugin, which actually makes those variables available in Maven "Goals and options", but those are set right after SCM checkout, i.e. before pre-build steps, and do not support expression evaluations.

sadrab
  • 7
  • 1
  • 1
  • 5
Jonas Bang Christensen
  • 1,041
  • 2
  • 10
  • 18

6 Answers6

40

You're on the right track here, but missed a third feature of the EnvInject-Plugin: The "Inject environment variables" build step that can inject variables into following build steps based on the result of a script or properties.

We're using the EnvInject plugin just like that; A script sets up a resource and communicates its parameters using properties that are then propagated by the plugin as environment variables.

i.e. setting up a temporary database for the build: Create a database for the build

jjungnickel
  • 1,264
  • 11
  • 9
  • Are you sure that your method makes the variables available to Maven "Goals and options"?? Because I did try "Inject environment variables", and it does make the variables accessible to e.g. post-build shells, but they are not available in Maven "Goals and options". – Jonas Bang Christensen Jul 31 '13 at 17:05
  • 1
    Yeah, that's exactly how we're doing it - that db.url is being passed to mvn … -Ddb.url=$db.url – jjungnickel Jul 31 '13 at 19:37
  • @JonasBang - What was your fix for making your variables available to the "goals and options" field? I'm currently running into the same issue with them being available to post-build steps, but not to the maven step. – Brian Creasy Feb 25 '14 at 20:32
  • 1
    Upon researching this further, I've found an actual fix for this issue. See my answer for a fix: http://stackoverflow.com/a/22048011/745417 – Brian Creasy Feb 26 '14 at 16:55
  • 4
    It's works for me only if i add a prefix : $WORKSPACE to the path of the file, otherwise the plugin doesn't find the file : `$WORKSPACE/env.properties` – herau Jul 22 '14 at 07:51
  • @JonasBang can you explain how you got it working? I have the same problem as you, the environment variables are available in post-build shells but not in Maven goals and options. Seeing as you accepted this answer I assume you found a way to make it work...? – Mekswoll Jul 09 '15 at 10:05
  • Ok I figured out that it doesn't work when Jenkins is running on the Windows machine but it does work when running on a Linux machine. Obviously on the windows machine I used %VAR% and on Linux ${VAR} – Mekswoll Jul 09 '15 at 13:09
  • i know this is a useless comment, but you just solved an issue i've been saving for quiet a long time!! thanks – Bamieh Aug 19 '16 at 19:34
10

I had a very similar problem, trying to compute a build version and inject it into the build. After running into all the same issues (not expanding, etc), I used the "Generate environment variables from script" option, which interprets the output as tag=value pairs into Jenkins variables. The script :

  #generate a version code that is high enough to surpass previously published clients
  val=`expr 150000 + $BUILD_NUMBER`
  echo VERSION_CODE=$val

After this, I was able to inject $VERSION_CODE into maven as follows :

  -Dbuild.vercode=${VERSION_CODE}

Hope that works for you.

Daniel Haley
  • 51,389
  • 6
  • 69
  • 95
user2797386
  • 101
  • 1
  • 2
  • 2
    For those looking for this option, it can be found in the Environment Script Plugin: https://wiki.jenkins-ci.org/display/JENKINS/Environment+Script+Plugin – Pmarcoen May 07 '15 at 09:23
3

This issue is caused by a bug in the Jenkins Maven Project Plugin as detailed in this bug report opened on 2012-06-22. The plugin has not yet been fixed as of version 2.1.

A fix has been proposed for the Maven Project Plugin, but has not yet been integrated. Here is the link to the pull request: https://github.com/jenkinsci/maven-plugin/pull/14

If you build the plugin yourself with the pull request patch applied, the variables are injected and made available to the "goals and options" field as expected.

Brian Creasy
  • 116
  • 1
  • 3
3

I see there is an accepted answer, but for a newbie in Jenkins I found it hard to grasp it all. That's why I would add a bit more detail in this answer and show how I did it.

As @jjungnickel suggested you need to have EnvInject Plugin installed for Jenkins. Then in the Build section > Add build step you'll get option "Inject environment variables".

Basically the idea is:

  1. Add variables you want to access later to a file (might be added by a shell script or it could be file from the file system).
  2. Inject the file with the variables.
  3. Use the variables.

Here a sample setup:

enter image description here

Since I want to use them in maven goal I need to check the Inject Build Variables checkbox.

Then at the end of the build I remove the file just because I want to keep the environment as it was before the build.

nyxz
  • 6,918
  • 9
  • 54
  • 67
0

I think your best shot is to try the EnvInject plugin for this along with your initial pre-scm step.

  1. You run the pre-scm as you already do.
  2. You use the env inject to load the file for the main job's build steps

Consider loading your file's content (properties format) or execute a script which will load the file as you want and make a variable available for the rest of the job with the "Prepare an environment for the run" option.

I hope this helps.

Eldad Assis
  • 10,464
  • 11
  • 52
  • 78
  • I can't use "Prepare an environment for the run" because "All these actions will be executed before a SCM checkout". The value which I need for my variable is taken from the SCM checkout. "Inject environment variables" does expand the expression correctly, and does make the variable available to other shells in the job, but it does not make it available to the actual Build step (i.e. Maven "Goals and options"). "Inject environment variables to the build process" does make the variable available to the actual Build step (i.e. Maven "Goals and options"), but it does not expand the expression. – Jonas Bang Christensen May 06 '13 at 13:14
  • Also, the "Inject environment variables to the build process" does inject after SCM checkout, so it seems like this is the option to use. Only problem is then how to get it to expand the expression: REVISION=$(cat .build_revision) ?? Currently is sets the variable as the string '$(cat .build_revision)', not the value from the file '.build_revision'. – Jonas Bang Christensen May 06 '13 at 13:18
  • I'm not sure you can execute a command in variables as you suggested. Maybe try REVISION=`cat .build_revision`. – Eldad Assis May 06 '13 at 14:39
  • Nope, that doesn't work either, it still set the variable to the string, not the expanded expression. Note that "Inject environment variables" does expand the expression, but "Inject environment variables to the build process" does not expand the expression. – Jonas Bang Christensen May 06 '13 at 21:49
0

I needed to resolve the variables before the injection was done so I put this in script content:

Example: (note it doesn't seem possible to simply export variables here so I wrote to files and the help section in jenkins seems to indicate this is expected)

git ls-tree --name-only -r ${sha1} | grep -v -c "*\.md" > diff.bak

git diff origin/master --shortstat | grep "1 files changed" && echo 1 > count.bak || echo 0 > count.bak

I then added this in the groovy script, using the output files I can create a map:

def procDiff = "cat $WORKSPACE/diff.bak".execute()
def procCount = "cat $WORKSPACE/count.bak".execute()
def diff = procDiff.text
def count = procCount.text

print "string val = $diff and count = $count "

if ("0".equals(diff) || !"1".equals(count)){
def map = ["GOAL": "clean verify"]
return map
} else {
def map = ["GOAL": "clean"]
return map
}

Then I could reference $GOAL in my maven build to conditionally trigger a "clean" or a "clean verify" based on the type of PR raised.

enter image description here