Alex Krasnyansky
Alex Krasnyansky

Reputation: 33

Passing Parameters to Ant from Jenkins Ant Plugin

I observe a strange behavior when trying to make a Jenkins project which has Ant steps accepting any String parameters to use by Ant. It so looks that Ant somehow receives some malformed content as parameters.

First I logged on the same system Jenkins installed on and wrote a simple ant build file:

<?xml version="1.0"?>
<!--DOCTYPE project PUBLIC "-//ANT//DTD project//EN" "/usr/src/ant/project.dtd"-->
<project name="many-params" default="run">
    <target name="run">
        <echo message="first Param: ${firstparam}"/>
        <echo message="second Param: ${secondparam}"/>
    </target>
</project>

I then ran the ant with parameters set and got the expected output:

$ ant -Dfirstparam=A -Dsecondparam=B
Buildfile: /tmp/build-dir/build.xml

run:
     [echo] first Param: A
     [echo] second Param: B

BUILD SUCCESSFUL
Total time: 0 seconds

Next up, I went to setting a project doing the same in Jenkins. My Jenkins systems specs follow:

I have set up the job of 8 consecutive steps, 4 preparatory shell script pieces that rewrite build.xml with slightly different parameter names (no separators, dash separators, dot separators) and 4 Ant build steps that call ant, trying to pass the corresponding parameters.

The ready config.xml from the job directory looks like:

<?xml version='1.0' encoding='UTF-8'?>                                                                                                                                                                                                  
<project>                                                                                                                                                                                                                               
  <actions/>                                                                                                                                                                                                                            
  <description>A simple task to test many parameter setting for jenkins calling ant tasks</description>                                                                                                                                 
  <logRotator class="hudson.tasks.LogRotator">                                                                                                                                                                                          
    <daysToKeep>-1</daysToKeep>                                                                                                                                                                                                         
    <numToKeep>10</numToKeep>                                                                                                                                                                                                           
    <artifactDaysToKeep>-1</artifactDaysToKeep>                                                                                                                                                                                         
    <artifactNumToKeep>-1</artifactNumToKeep>                                                                                                                                                                                           
  </logRotator>                                                                                                                                                                                                                         
  <keepDependencies>false</keepDependencies>                                                                                                                                                                                            
  <scm class="hudson.scm.NullSCM"/>                                                                                                                                                                                                     
  <canRoam>true</canRoam>                                                                                                                                                                                                               
  <disabled>false</disabled>                                                                                                                                                                                                            
  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>                                                                                                                                                            
  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>                                                                                                                                                                
  <jdk>Oracle Java 1.6.45 32-bit JRE</jdk>                                                                                                                                                                                              
  <triggers/>                                                                                                                                                                                                                           
  <concurrentBuild>false</concurrentBuild>                                                                                                                                                                                              
  <builders>                                                                                                                                                                                                                            
    <hudson.tasks.Shell>                                                                                                                                                                                                                
      <command>echo &quot;STEP 1: Pass parameters with no separators in names&quot;                                                                                                                                                     
cat &gt; build.xml &lt;&lt; EOF                                                                                                                                                                                                         
&lt;?xml version=&quot;1.0&quot;?&gt;                                                                                                                                                                                                   
&lt;!--DOCTYPE project PUBLIC &quot;-//ANT//DTD project//EN&quot; &quot;/usr/src/ant/project.dtd&quot;--&gt;                                                                                                                            
&lt;project name=&quot;many-params&quot; default=&quot;run&quot;&gt;                                                                                                                                                                    
    &lt;target name=&quot;run&quot;&gt;                                                                                                                                                                                                 
        &lt;echo message=&quot;first Param: ${paramfirst}&quot;/&gt;                                                                                                                                                                    
        &lt;echo message=&quot;second Param: ${paramsecond}&quot;/&gt;                                                                                                                                                                  
    &lt;/target&gt;                                                                                                                                                                                                                     
&lt;/project&gt;                                                                                                                                                                                                                        
EOF</command>                                                                                                                                                                                                                           
    </hudson.tasks.Shell>                                                                                                                                                                                                               
    <hudson.tasks.Ant plugin="[email protected]">                                                                                                                                                                                                 
      <targets>run</targets>                                                                                                                                                                                                            
      <antName>Ant 1.8.2</antName>                                                                                                                                                                                                      
      <properties>paramfirst=A                                                                                                                                                                                                          
paramsecond=B</properties>                                                                                                                                                                                                              
    </hudson.tasks.Ant>                                                                                                                                                                                                                 
    <hudson.tasks.Shell>                                                                                                                                                                                                                
      <command>rm build.xml
echo
echo &quot;STEP 2: Pass parameters with separated by dashes in names&quot;
cat &gt; build.xml &lt;&lt; EOF
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;!--DOCTYPE project PUBLIC &quot;-//ANT//DTD project//EN&quot; &quot;/usr/src/ant/project.dtd&quot;--&gt;
&lt;project name=&quot;many-params&quot; default=&quot;run&quot;&gt;
    &lt;target name=&quot;run&quot;&gt;
        &lt;echo message=&quot;first Param: ${param-first}&quot;/&gt;
        &lt;echo message=&quot;second Param: ${param-second}&quot;/&gt;
    &lt;/target&gt;
&lt;/project&gt;
EOF</command>
    </hudson.tasks.Shell>
    <hudson.tasks.Ant plugin="[email protected]">
      <targets>run</targets>
      <antName>Ant 1.8.2</antName>
      <properties>param-first=A
param-second=B</properties>
    </hudson.tasks.Ant>
    <hudson.tasks.Shell>
      <command>echo
echo &quot;STEP 3: Same, but with parameters on the same line in Ant Plugin step setup&quot;</command>
    </hudson.tasks.Shell>
    <hudson.tasks.Ant plugin="[email protected]">
      <targets>run</targets>
      <antName>Ant 1.8.2</antName>
      <properties>param-first=A param-second=B</properties>
    </hudson.tasks.Ant>
    <hudson.tasks.Shell>
      <command>rm build.xml
echo
echo &quot;STEP 4: Pass parameters with separated by dots in names&quot;
cat &gt; build.xml &lt;&lt; EOF
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;!--DOCTYPE project PUBLIC &quot;-//ANT//DTD project//EN&quot; &quot;/usr/src/ant/project.dtd&quot;--&gt;
&lt;project name=&quot;many-params&quot; default=&quot;run&quot;&gt;
    &lt;target name=&quot;run&quot;&gt;
        &lt;echo message=&quot;first Param: ${param.first}&quot;/&gt;
        &lt;echo message=&quot;second Param: ${param.second}&quot;/&gt;
    &lt;/target&gt;
&lt;/project&gt;
EOF</command>
    </hudson.tasks.Shell>
    <hudson.tasks.Ant plugin="[email protected]">
      <targets>run</targets>
      <antName>Ant 1.8.2</antName>
      <properties>param.first=A
param.second=B</properties>
    </hudson.tasks.Ant>
  </builders>
  <publishers/>
  <buildWrappers>
    <hudson.plugins.ws__cleanup.PreBuildCleanup plugin="[email protected]">
      <deleteDirs>false</deleteDirs>
      <cleanupParameter></cleanupParameter>
      <externalDelete></externalDelete>
    </hudson.plugins.ws__cleanup.PreBuildCleanup>
  </buildWrappers>
</project>

Building the task gave me the following output:

Started by user Alexander Krasnyansky
[EnvInject] - Loading node environment variables.
Building remotely on j03_uk1ps41 (buildslaves) in workspace /var/lib/jenkins03/workspace/akrasnyansky/ManyParams/ant-param-test

Deleting project workspace... done

[ant-param-test] $ /bin/sh -xe /tmp/hudson2203137136163442442.sh
+ echo 'STEP 1: Pass parameters with no separators in names'
STEP 1: Pass parameters with no separators in names
+ cat
[ant-param-test] $ /usr/local/apache-ant-1.8.2/bin/ant -Dparamfirst=A -Dparamsecond=B run
Buildfile: /var/lib/jenkins03/workspace/akrasnyansky/ManyParams/ant-param-test/build.xml

run:
     [echo] first Param: 
     [echo] second Param: 

BUILD SUCCESSFUL
Total time: 0 seconds
[ant-param-test] $ /bin/sh -xe /tmp/hudson5869719507232196626.sh
+ rm build.xml
+ echo

+ echo 'STEP 2: Pass parameters with separated by dashes in names'
STEP 2: Pass parameters with separated by dashes in names
+ cat
[ant-param-test] $ /usr/local/apache-ant-1.8.2/bin/ant -Dparam-first=A -Dparam-second=B run
Buildfile: /var/lib/jenkins03/workspace/akrasnyansky/ManyParams/ant-param-test/build.xml

run:
     [echo] first Param: first
     [echo] second Param: second

BUILD SUCCESSFUL
Total time: 0 seconds
[ant-param-test] $ /bin/sh -xe /tmp/hudson1052316660761572548.sh
+ echo

+ echo 'STEP 3: Same, but with parameters on the same line in Ant Plugin step setup'
STEP 3: Same, but with parameters on the same line in Ant Plugin step setup
[ant-param-test] $ /usr/local/apache-ant-1.8.2/bin/ant "-Dparam-first=A param-second=B" run
Buildfile: /var/lib/jenkins03/workspace/akrasnyansky/ManyParams/ant-param-test/build.xml

run:
     [echo] first Param: first
     [echo] second Param: second

BUILD SUCCESSFUL
Total time: 0 seconds
[ant-param-test] $ /bin/sh -xe /tmp/hudson4427994032931026249.sh
+ rm build.xml
+ echo

+ echo 'STEP 4: Pass parameters with separated by dots in names'
STEP 4: Pass parameters with separated by dots in names
+ cat
/tmp/hudson4427994032931026249.sh: line 5: <?xml version="1.0"?>
<!--DOCTYPE project PUBLIC "-//ANT//DTD project//EN" "/usr/src/ant/project.dtd"-->
<project name="many-params" default="run">
    <target name="run">
        <echo message="first Param: ${param.first}"/>
        <echo message="second Param: ${param.second}"/>
    </target>
</project>
: bad substitution
Build step 'Execute shell' marked build as failure
Started calculate disk usage of build
Finished Calculation of disk usage of build in 0 seconds
Started calculate disk usage of workspace
Finished Calculation of disk usage of workspace in 0 seconds
Finished: FAILURE

So this arises many questions:

  1. Why no values are printed at all at STEP 1?
  2. How it came to using string values "first" and "second" instead of "A" and "B" I supplied at STEP 2?
  3. Why at STEP 3 malformed line "-Dparam-first=A param-second=B" (produced by putting both parameters on the same line in Jenkins step setup: param-first=A param-second=B) works just as well as "-Dparam-first=A -Dparam-second=B" at STEP 2? I was supposed to fail here, as happens when I run the same in the shell.
  4. What is wrong with the dots at STEP 4? Why does it produce a bad substitution error here?

Many thanks for any advise on these issues.

Upvotes: 3

Views: 5303

Answers (1)

Slav
Slav

Reputation: 27485

Your problem is with the re-writing of the build.xml. I honestly don't understand why you are doing that. But let's dive in.

tl;dr: You are confusing behaviour of Shell and Ant variables: how to escape them and what happens when they are undefined.

You have an "Execute Shell" build step, and there you use cat to put new content into file.

Stop right there. Either delete your other build steps, or simply put a huge sleep after the cat command. Now look inside your workspace for the generated build.xml. You will see:
<echo message="first Param: "/>

As you can see, there is actually no parameter in that echo line. So not surprisingly when it runs, it doesn't print anything other than text. Why did that happen?

1. Your cat command runs in Shell. You are not escaping the param's dollar sign $ in first Param: ${paramfirst}. Therefore, at run-time, Shell sees ${paramfirst} as a variable and tries to find it's value. There isn't one, so Shell substitutes it with nothing (if this was Ant, Ant would have printed the undefined variable verbatim)

You need to escape the variable from Shell, therefore write first Param: \${paramfirst}. This will generate the correct build.xml and all will work from there.

2. Allowed characters in linux environment variable names or Can shell variable include - character?
A hyphen - is not an allowed Shell variable name.

What happens is that after Shell sees the variable definition ${ it looks ahead upto the hyphen - (cause hyphen cannot be a variable name), and splits the string there. So out of ${param-first}, Shell thinks that ${param is variable and -first} is malformed text. The first is substituted with nothing, and the remainder is printed (with } being consumed due to Shell idiosyncrasies)

3. The "Invoke Ant" build step expects params in key=value fashion, one per line. It will then take each line, prefix it with -D and string multiple lines together forming the final command line.

So this:

param-first=A
param-second=B

Becomes this:

-Dparam-first=A
-Dparam-second=B

And then strung together as: -Dparam-first=A -Dparam-second=B

When you did this:

param-first=A param-second=B

It become this (remember: one per line):

-Dparam-first=A param-second=B

Notice only one -D as it's one param per line

4. Shell does not allow periods . in variable names. Period. (Pun intended). See the answer to 1. and 2.. You could however use the periods and hyphens in Ant variable names, but I would advise against that for consistency reasons.

Upvotes: 1

Related Questions