Asking user for yes|no input - ant

I am working on an Ant build process for an application that uses a versioning in the following format: major.minor.buildcount. So currently the application is around 2.1.52, where we are on version 2.1 and there have been 35 builds.
I am now adding in an ant target to ask the user if they would like to advance the major version and/or the minor version.
When I run my target from the command line I would like to follow the following:
## ant version
Versioning application...
Would you like to advance the major version to 3? (Y|n)
## n
Not Advancing major version
Would you like to advance the minor version to 2? (y|N)
## y
Advancing minor version
The lines prepended with ## is the user input that I would like to take. My major and minor versions are stored in a build.properties file.
Here is my code so far
<?xml version="1.0"?>
<project name="StudentMS" default="zip" basedir=".">
<propertyfile file="./.ant/build.properties">
<entry key="version.buildnumber" type="int" default="0" operation="+" pattern="00" />
</propertyfile>
<property file="./.ant/build.properties" />
<property name="sourceDir" location="/Users/dave/Workspace/ColdFusion/StudentMs" />
<property name="buildDir" location="${sourceDir}/builds" />
<target name="version" description="Adds a major and minor version to the build.">
<input message="Advance major version? ${version.major}" addproperty="updatemajor" validargs="y,n" defaultvalue="n" />
<propertyfile file="./.ant/build.properties">
<entry key="version.major" type="int" default="0" operation="+" pattern="00" />
</propertyfile>
<input message="Advance minor version? ${version.minor}" addproperty="updateminor" validargs="y,n" defaultvalue="y" />
<propertyfile file="./.ant/build.properties">
<entry key="version.minor" type="int" default="0" operation="+" pattern="00" />
</propertyfile>
</target>
</project>
And my build.properties
#Tue, 29 Mar 2011 11:46:30 -0400
version.buildnumber=35
version.major=2
version.minor=1
I am still very new to Ant so I am sorry that I can't post more advanced code. So the first thing I need to do is add some kind of conditional around my property file edits.

what you want can be achieved by combining the condition and antcall task and by adding a couple of extra targets.
I think something like this should work:
<property file="./.ant/build.properties" />
<property name="sourceDir" location="/Users/dave/Workspace/ColdFusion/StudentMs" />
<property name="buildDir" location="${sourceDir}/builds" />
<target name="version" description="Adds a major and minor version to the build.">
<input message="Advance major version? ${version.major}" addproperty="updatemajor" validargs="y,n" defaultvalue="n" />
<condition property="executeMajor">
<and>
<isset property="updatemajor" />
<equals arg1="${updatemajor}" arg2="y" />
</and>
</condition>
<antcall target="update_major" />
<input message="Advance minor version? ${version.minor}" addproperty="updateminor" validargs="y,n" defaultvalue="y" />
<condition property="executeMinor">
<and>
<isset property="updateminor" />
<equals arg1="${updateminor}" arg2="y" />
</and>
</condition>
<antcall target="update_minor" />
</target>
<target name="update_major" if="executeMajor">
<!-- Code to update major here -->
</target>
<target name="update_minor" if="executeMinor">
<!-- Code to update minor here -->
</target>
Basically, what it does is set the executeMajor and executeMinor properties just in the case that the updatemajor/updateminor are set to "y". Then, ant will run the update targets just if the executeMajor/Minor variables are set, and it will skip them otherwise.

An alternative would support both user input and an unattended build.
You can define ant properties on the command line. So, when you want to advance a version, you could do something like this:
ant -Dbuild.version.advanceMinor=true
This approach would also allow you to avoid the extra steps on the majority of builds.

Related

How to validate the parameter is uppercase in Jenkins using ANT

I have a Jenkins build and in that I am providing a build parameter with uppercase value (Build parameter should be uppercase always), by chance if a user is providing a lower case value, the build should gets failed.
Kindly provide inputs on how to check the provided Jenkins build parameter provided is uppercase or a lowercase using ANT. Thanks!
This can be accomplished using Ant's matches condition. A nested regexp is used in the below example to avoid repetition.
<target name="check-uppercase">
<property name="test1" value="lowercase" />
<property name="test2" value="MixedCase" />
<property name="test3" value="UPPERCASE" />
<regexp id="all.uppercase" pattern="^[A-Z]+$" />
<condition property="test1.isUppercase" value="true" else="false">
<matches string="${test1}">
<regexp refid="all.uppercase" />
</matches>
</condition>
<condition property="test2.isUppercase" value="true" else="false">
<matches string="${test2}">
<regexp refid="all.uppercase" />
</matches>
</condition>
<condition property="test3.isUppercase" value="true" else="false">
<matches string="${test3}">
<regexp refid="all.uppercase" />
</matches>
</condition>
<echo message="test1 uppercase? ${test1.isUppercase}" />
<echo message="test2 uppercase? ${test2.isUppercase}" />
<echo message="test3 uppercase? ${test3.isUppercase}" />
</target>

how to ignore a failure ant task?

I have this ant script that is reading from a parameter a list of components and running other ant tasks (build.xml's):
<for list="${components.locations}" param="component" failonany="false">
<sequential>
<property name="#{component}" value="true"/>
<if>
<and>
<available file="${repository.location}/#{component}"/>
<available file="${repository.location}/${jars.location}"/>
</and>
<then>
<ant inheritAll="false" antfile="${repository.location}/#{component}/build.xml">
<!-- failonerror="false" -->
<property name="copy.libs" value="${copy.libs}"/>
<property name="repository.location" value="${repository.location}"/>
<property name="jars.location" value="${repository.location}/${jars.location}"/>
</ant>
</then>
</if>
</sequential>
</for>
The problem is if one component is failing, the script doesn't continue to next one.
I tried running with -k (-keep-going) argument but it doesn't help.
I found this property failonerror="false" but it's valid for "exec" tasks and couldn't integrate it with "ant" tasks or inside a "target".
Other direction was "failonany" property of the "for" but I didn't manage setting it up explicitly.
Can you please advice...
Thanks.
First of all, I would suggest deleting ant-contrib.jar and never looking back. Believe me, you will be doing yourself a favor.
You can use the subant task to iterate Ant builds on a set of directories or files. Simply define a dirset and pass any extra properties you need.
Instead of using ant-contrib's <if> block, use the standard target's if attribute to switch the entire target on or off. This is much safer and better practice.
<property name="repository.location" location="repository_location" />
<property name="jars.location" location="${repository.location}/jars" />
<property name="components" value="dir1,dir2,dir3" />
<target name="init">
<condition property="jars.available">
<available file="${jars.location}" />
</condition>
</target>
<target name="default" depends="init" if="jars.available">
<subant inheritall="false" failonerror="false">
<dirset id="components.dirs" dir="${repository.location}" includes="${components}" />
<property name="copy.libs" value="${copy.libs}" />
<property name="repository.location" value="${repository.location}" />
<property name="jars.location" value="${jars.location}" />
</subant>
</target>

Generating HTML report with Ant 1.9.7 from Jmeter 3.0 file - "Start and end within the same entity" Error

Here is basically the build.xml that Jmeter 3.0 generated itself. When I try to run the tests with 40 000 users within an hour I get the error after 17 minutes - "${path}/build.xml: Fatal error during transformation using ${path}/jmeter-results-detail-report_21.xsl: XML document structures must start and end within the same entity.; SystemID: file:${path}/Test.jtl;"
<?xml version="1.0"?>
<project name="ant-jmeter" default="all">
<property name="testpath" value="${user.dir}"/>
<property name="jmeter.home" value="${basedir}/.."/>
<property name="report.title" value="Load Test Results"/>
<property name="target.report.dir" location="Asjad/apache-jmeter-3.0/extras/report"/>
<property name="test" value="Test"/>
<property name="show-data" value="n"/>
<property name="format" value="2.1"/>
<condition property="style_version" value="">
<equals arg1="${format}" arg2="2.0"/>
</condition>
<condition property="style_version" value="_21">
<equals arg1="${format}" arg2="2.1"/>
</condition>
<condition property="funcMode">
<equals arg1="${show-data}" arg2="y"/>
</condition>
<condition property="funcMode" value="false">
<not>
<equals arg1="${show-data}" arg2="y"/>
</not>
</condition>
<path id="jmeter.classpath">
<fileset dir="${basedir}">
<include name="ant-jmeter*.jar"/>
</fileset>
</path>
<taskdef
name="jmeter"
classpathref="jmeter.classpath"
classname="org.programmerplanet.ant.taskdefs.jmeter.JMeterTask"/>
<target name="all" depends="run,report"/>
<target name="run">
<echo>funcMode = ${funcMode}</echo>
<delete file="${testpath}/${test}.html"/>
<delete file="${testpath}/${test}.jtl"/>
<jmeter
jmeterhome="${jmeter.home}"
testplan ="${testpath}/${test}.jmx"
resultlog="${testpath}/${test}.jtl">
<property name="jmeter.save.saveservice.output_format" value="xml"/>
<property name="jmeter.save.saveservice.assertion_results" value="all"/>
<property name="jmeter.save.saveservice.bytes" value="true"/>
<property name="file_format.testlog" value="${format}"/>
<property name="jmeter.save.saveservice.response_data.on_error" value="${funcMode}"/>
</jmeter>
</target>
<property name="lib.dir" value="${jmeter.home}/lib"/>
<path id="xslt.classpath">
<fileset dir="${lib.dir}" includes="xalan*.jar"/>
<fileset dir="${lib.dir}" includes="serializer*.jar"/>
</path>
<target name="report" depends="xslt-report">
<echo>Report generated at ${report.datestamp}</echo>
</target>
<target name="xslt-report" depends="_message_xalan">
<tstamp><format property="report.datestamp" pattern="yyyy/MM/dd HH:mm"/></tstamp>
<xslt
classpathref="xslt.classpath"
force="true"
in="${testpath}/${test}.jtl"
out="${testpath}/${test}.html"
style="${basedir}/jmeter-results-detail-report_21.xsl">
<param name="showData" expression="${show-data}"/>
<param name="titleReport" expression="${report.title}"/>
<param name="dateReport" expression="${report.datestamp}"/>
</xslt>
</target>
<condition property="xalan.present">
<and>
<available classpathref="xslt.classpath" classname="org.apache.xalan.processor.TransformerFactoryImpl"/>
<available classpathref="xslt.classpath" classname="org.apache.xml.serializer.ExtendedContentHandler"/>
</and>
</condition>
<target name="_message_xalan" unless="xalan.present">
<echo>Cannot find all xalan and/or serialiser jars</echo>
<echo>The XSLT formatting may not work correctly.</echo>
<echo>Check you have xalan and serializer jars in ${lib.dir}</echo>
</target>
</project>
It is a simple test that just makes requests to the webpage.
I am using Ant build 1.9.7 and Jmeter 3.0.
I can think of 2 possible reasons:
Ant might be trying to convert .jtl to HTML when the .jtl is incomplete. In order to work that around:
Add the next line to <jmeter> section:
<property name="jmeter.save.saveservice.autoflush" value="true"/>
Or alternatively put add the following line to user.properties file (lives in JMeter's "bin" folder)
jmeter.save.saveservice.autoflush=true
It will "tell" JMeter to store the results as soon as they arrive.
40 000 users is quite a "heavy" load and JMeter default configuration might not be suitable for this. I believe you need to add at least some Java Heap space. In case of Ant it would be adding the next lines to <jmeter> section:
<jvmarg value="-Xmx8G"/>
Change that 8G reference value to be around 80% of your available physical RAM. See 9 Easy Solutions for a JMeter Load Test “Out of Memory” Failure guide for more recommendations on JMeter tuning for maximum performance
Showing your jmeter.log file (jmeter 3.0 will tell you where it is generated) will help.
But you may be facing this bug if using ANT + XSL to generated report:
https://bz.apache.org/bugzilla/show_bug.cgi?id=59918
See this :
Generating a faulty report when running JMeter 3.0 test with Ant

How can i edit path of a jar in ant

I would like to replace path of an existing jar based on OS .
some thing like below:
in windows : C:/apps/workspace/libs/rpm.jar
in unix : /user-id/projectname/libs/rpm.jar
Is there a way to remove C:/apps/workspace/libs from C:/apps/workspace/libs/rpm.jar .
editing my Question to :
Thanks Liv, But i have lot of libraries like this. right now i am maintaning a text file called "build.start.properties" with all libraries some ting like this
/gwt/X/2.1.0/gwt-servlet.jar
/gwt/X/2.1.0/gwt-user.jar
/gwt/X/2.1.0/gwt-dev.jar
/gwt/X/2.1.0/gwt-soyc-vis.jar
/log4j/X/1.2.15/log4j-1.2.15.jar
/GWT_LOG/X/3.0.3/gwt-log-3.0.3.jar
/GWT_MATH/X/2.1/gwt-math-2.1.jar
/GWT_MATH/X/2.1/gwt-math-server-2.1.jar
/GWT_Commons_Logging/X/0.3/GWT-commons-logging/gwt-commons-logging-0.3.jar
/GWT_Commons_Logging/X/0.3/GWT-commons-logging/gwt-commons-logging-service-0.3.jar
And loading them to classptah using below target
<loadfile property="jars.list.property" srcfile="mybuild/build.start.properties">
<filterchain>
<expandproperties />
<striplinecomments>
<comment value="#" />
</striplinecomments>
<tokenfilter>
<ignoreblank />
</tokenfilter>
<prefixlines prefix="," />
<striplinebreaks />
</filterchain>
</loadfile>
<filelist id="build.libs" dir="" files="${jars.list.property}" />
<pathconvert targetos="unix" property="build_unix.libs" refid="build.libs">
<map from="C:" to="${unix.xenv}" />
<map from="" to="${unix.xenv}" />
</pathconvert>
<pathconvert targetos="windows" property="build_windows.libs" refid="build.libs">
<map from="C:" to="${windows.xenv}" />
<map from="" to="${windows.xenv}" />
</pathconvert>
<path id="build.classpath.id">
<pathelement path="${build_windows.libs}" />
<pathelement path="${build_unix.libs}" />
</path>
<echo message="Build Libraries classpath: ${toString:build.classpath.id}" />
</target>
from the above target build.classpath.id looks like
/gwt/X/2.1.0/gwt-servlet.jar:/gwt/X/2.1.0/gwt-user.jar:/gwt/X/2.1.0/gwt-dev.jar:/gwt/X/2.1.0/gwt-soyc-vis.jar:/log4j/X/1.2.15/log4j-1.2.15.jar:/GWT_LOG/X/3.0.3/gwt-log-3.0.3.jar:GWT_MATH/X/2.1/gwt-math-2.1.jar:/GWT_MATH/X/2.1/gwt-math-server-2.1.jar:/GWT_Commons_Logging/X/0.3/GWT-commons-logging/gwt-commons-logging-0.3.jar:/GWT_Commons_Logging/X/0.3/GWT-commons-logging/gwt-commons-logging-service-0.3.jar
When i work on unix I have to pic only jar names from file "build.start.properties" and update path like this
/WebContent/WEB_INF/lib/gwt-servlet.jar:/WebContent/WEB_INF/lib/gwt-user.jar:/WebContent/WEB_INF/lib/gwt-dev.jar:/WebContent/WEB_INF/lib/gwt-soyc-vis.jar:/WebContent/WEB_INF/lib/log4j-1.2.15.jar:/WebContent/WEB_INF/lib/gwt-log-3.0.3.jar:/WebContent/WEB_INF/lib/gwt-math-2.1.jar:/WebContent/WEB_INF/lib/gwt-math-server-2.1.jar:/WebContent/WEB_INF/lib/gwt-commons-logging-0.3.jar:/WebContent/WEB_INF/lib/gwt-commons-logging-service-0.3.jar
Always use relative paths, that way you wont' be relying on library being at given location and on underlying OS.
Although this does not answer what you exactly asked for, but the suggestion will help you in the long run. Also, if possible, use Ivy + Ant (or Maven) to manage dependency.
you can use the ant task -- the folliwng is taken from the documentation (http://ant.apache.org/manual/Tasks/condition.html):
<condition property="isMacOsButNotMacOsX">
<and>
<os family="mac"/>
<not>
<os family="unix"/>
</not>
</and>
</condition>

Testing Macrodef Attribute without IF

I am attempting to remove all lines that begin with log if a macrodef attribute is set to prod (example below). I plan on using replaceregexp to remove all lines beginning with log. However, I am not sure how to test if an attribute is set to a specific value, besides using the if task. I would like to not introduce any non-core Ant tasks to perform this, but I can't come up with any other solutions. Do I have any other options besides using the if-task?
Thanks
<macrodef name="setBuildstamp">
<attribute name="platform" />
<sequential>
<if>
<equals arg1="platform" arg2="prod" />
<then>
<replaceregexp match="^log\(.*" value="" />
</then>
</if>
</sequential>
</macrodef>
You should use a reference to a parameter, like this #{platform}.
Also, your replaceregexp task is missing a few parameters.
I think that in your particular case it is better to use linecontainsregexp filter reader. Here is modified code (note negate argument to linecontainsregexp).
<macrodef name="setBuildstamp">
<attribute name="platform" />
<sequential>
<if>
<equals arg1="#{platform}" arg2="prod" />
<then>
<copy todir="dest-dir">
<fileset dir="src-dir"/>
<filterchain>
<linecontainsregexp
regexp="^log\(.*"
negate="true"
/>
</filterchain>
</copy>
</then>
</if>
</sequential>
</macrodef>
They may be a couple of ways to solve this, but none are as straightforward as using the ant-contrib element. I'm not sure if this will get you what you need for your application, but you could try the following:
Using conditional targets. If you can replace your macrodef with a target to call, this may work for you. Note that this will set the property globally, so it might not work for your application.
<target name="default">
<condition property="platformIsProd">
<equals arg1="${platform}" arg2="prod" />
</condition>
<antcall target="do-buildstamp" />
</target>
<target name="do-buildstamp" if="platformIsProd">
<echo>doing prod stuff...</echo>
</target>
Handle the 'else' case. If you need to handle an alternate case, you'll need to provide a few targets...
<target name="default">
<property name="platform" value="prod" />
<antcall target="do-buildstamp" />
</target>
<target name="do-buildstamp">
<condition property="platformIsProd">
<equals arg1="${platform}" arg2="prod" />
</condition>
<antcall target="do-buildstamp-prod" />
<antcall target="do-buildstamp-other" />
</target>
<target name="do-buildstamp-prod" if="platformIsProd">
<echo>doing internal prod stuff...</echo>
</target>
<target name="do-buildstamp-other" unless="platformIsProd">
<echo>doing internal non-prod stuff...</echo>
</target>
Using an external build file. If you need to make multiple calls with different values for your property, you could isolate this in another build file within the same project. This creates a bit of a performance hit, but you would not need the additional library.
in build.xml:
<target name="default">
<ant antfile="buildstamp.xml" target="do-buildstamp" />
<ant antfile="buildstamp.xml" target="do-buildstamp">
<property name="platform" value="prod" />
</ant>
<ant antfile="buildstamp.xml" target="do-buildstamp">
<property name="platform" value="nonprod" />
</ant>
</target>
in buildstamp.xml:
<condition property="platformIsProd">
<equals arg1="${platform}" arg2="prod" />
</condition>
<target name="do-buildstamp">
<antcall target="do-buildstamp-prod" />
<antcall target="do-buildstamp-other" />
</target>
<target name="do-buildstamp-prod" if="platformIsProd">
<echo>doing external prod stuff...</echo>
</target>
<target name="do-buildstamp-other" unless="platformIsProd">
<echo>doing external non-prod stuff...</echo>
</target>
Add ant-contrib to your project. Of course, if you can add a file to your project, the easiest thing would be to just add the ant-contrib.jar file. You could put it under a "tools" folder and pull it in using a taskdef:
<taskdef resource="net/sf/antcontrib/antlib.xml" classpath="${basedir}/tools/ant-contrib.jar" />
It looks like when you are building your project specifically for your Production environment - you are stripping out code you don't want to run in Production. Thus you are creating a different binary than what will run in your Dev or Testing environment.
How about using an environment variable or property file at run-time instead of build-time which determines whether or not logging happens? This way when you're having trouble in Production and you want to use the same exact binary (instead of determining the revision, checking out the code, rebuilding with a different environment flag) you just re-deploy it to your Dev or Test environment and turn on debugging in a properties file or environment variable?

Resources