33
votes

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.

6

6 Answers

38
votes

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

10
votes

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.

3
votes

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.

3
votes

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.

0
votes

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.

0
votes

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