ant task to generate mutiple targets in different project - ant

i have ant target which invokes simultaneously other 3 projects ant build target for junit. this build target executes all three projects even though any one of the project build fails. Problem here is, if any one of the build fails error message should display after compiling three projects build target but it is not happening, how can i solve it?
<target name="mainbuild">
<antcall target="junit-1">//in different project
<antcall target="junit-2">//in different project
<antcall target="junit-3">//in different project
<junitreport todir="./reports">
<fileset dir="./project-1/reports">
<include name="TEST-*.xml"/>
</fileset>
<fileset dir="./project-2/reports">
<include name="TEST-*.xml"/>
</fileset>
<fileset dir="./project-3/reports">
<include name="TEST-*.xml"/>
</fileset>
<report format="frames" todir="./report/html"/>
</junitreport>
</target>
<target name="junit-1">
.... do somethig
</target>
<target name="junit-2">
.... do somethig
</target>
<target name="junit-3">
.... do somethig
</target>
1) main build invokes 3 project,even though build fail in any one of the sub project, build successful message displays at the end, it shouldn't happen
2) if any one the sub project build fails, build report should generate, so that developer can analyze further on his failure.

Since you have clarified that your targets are in different projects, i.e. different build files, you will have to use the ant or subant tasks instead of antcall. The subant task has a parameter called failonerror which you can set to false so that a failure will not stop the top-level build. I don't know if it is possible to pass back to the top-level build the information that a sub-project build has actually failed its tests.
If your targets were all in the same project you could change your junit tasks so that they don't fail if a test fails, but instead set a property to indicate that a failure has occurred:
<junit failureProperty="test.failed"> ... </junit>
Then you can make your mainbuild target fail after generating the JUnit report:
<fail if="test.failed"> ... </fail>
I learned this from the book "Ant in Action".

Related

How to use one target in multiple targets' 'depends' property in ANT build?

I am using ANT build for deployment process. For that, I followed the below points,
Created five targets in ANT named 'initiate.deploy' (to initiate
deployment), 'svn.checkout' (checkout source from SVN into
workspace) , 'generate.ear' (EAR generation) and 'deploy.ear'
(deploy EAR into Server), 'clean.workspace' (Cleaning workspace
dirtory).
The target 'initiate.deploy' is my default target.
I need to clean the workspace directory before 'svn.checkout' target
and after 'deploy.ear' target.
I put 'clean.workspace' target in 'depends' property of
'svn.checkout' target and in 'initiate.deploy' target.
My Code:
<target name="initiate.deploy" description="Initiate deployment" depends="svn.checkout, generate.ear, deploy.ear, clean.workspace">
..........................
</target>
<target name="svn.checkout" description="SVN checkout" depends ="clean.workspace">
..........................
</target>
But the target 'clean.workspace' is executed only once before 'svn.checkout' but not after 'deploy.ear' target.
Build sequence is created as follows.
Build sequence for target(s) 'initiate.deploy' is [clean.workspace,
svn.checkout, check.workSpace, update.property.file, generate.ear,
deploy.ear, initiate.deploy]
How to use one target in multiple targets' 'depends' property in ANT build?
As explained in the Ant documentation:
In a chain of dependencies stretching back from a given target such as
D above, each target gets executed only once, even when more than one
target depends on it.
My understanding is that this is designed to avoid cycles in the dependencies graph.
Due to this, you need to modify your targets, for example by removing clean.workspace from the dependencies of initiate.deploy and invoking it explicitely via the antcall task:
<target name="initiate.deploy" description="Initiate deployment" depends="svn.checkout, generate.ear, deploy.ear">
..........................
<antcall target="clean.workspace" />
</target>
<target name="svn.checkout" description="SVN checkout" depends ="clean.workspace">
..........................
</target>
Update:
As mentioned in the comments, the antcall task will start the invoked target in a new Ant project, which can create an undesirable overhead. To avoid this behavior, it is possible to wrap the target as a macrodef and invoke it as a task in any other target. You may then change the invoked target such that it calls the new macrodef, in order to keep it available as a dependency of other tasks:
<target name="initiate.deploy" description="Initiate deployment" depends="svn.checkout, generate.ear, deploy.ear">
..........................
<clean.workspace.macro />
</target>
<target name="svn.checkout" description="SVN checkout" depends ="clean.workspace">
..........................
</target>
<target name="clean.workspace">
<clean.workspace.macro />
</target>
<macrodef name="clean.workspace.macro">
<sequential>
<!-- do the workspace cleanup -->
..........................
</sequential>
</macrodef>

Build multiple environments with a single target and single command(Anding -D and property file)

I have to create a single command to create multiple(dev|qa|uat) war/ear.
Something like :
ant -f build.xml -Denv=dev|qa|uat -propertyfile= devProp|qaProp|uatProp
-Dstage.dir=devdir|qadir|uatdir
I already have different properties file, different staging, deploying target for each environment. I also have different .cmd files to build each of them separately.
What I am stuck at is: How do I build them all in one go?
You can use the <subant /> instruction in your target.
Write down a new ant script (namely master.xml), assuming that your original build is in script build.xml, you can have something like:
<target name="build-all">
<subant target="build-prod">
<fileset dir="." includes="build.xml"/>
<propertyset ......../> <!-- properties for the prod build -->
</subant>
<subant target="build-dev">
<fileset dir="." includes="build.xml"/>
<propertyset ......../> <!-- properties for the dev build -->
</subant>
</target>

How to show Assembled Ant Classpath

I'm developing a Java project using Eclipse, and Ant as a build tool. When I run "ant all" from the command line, my project builds without any errors, but on Eclipse I get many compilation errors.
So I thought I'd copy Ant's Classpath onto my Eclipse Project's Build Path.
Is there an Ant task/command to show that? Like "ant just show me your assembled classpath" or something?
If you run Ant with the -verbose and -debug flags, you'll see all gory details of what javac is doing, including the classpath.
I would introduce a task for printing the classpath, and call that task with antcall. The classpath would be given as a parameter to that task.
You can do something like this in your target, so for example
lets say you've defined your classpath as
<path id="project.classpath">
<fileset dir="${SERVER_DEV}/classes">
<include name="*.zip"/>
<include name="*.jar"/>
</fileset>
<pathelement location="${SERVER_DEV}/3rdParty/jre/NT/1.5.0/lib/jsse.jar"/>
</path>
then you can do something like
<target name="compile" depends="init" description="Compiles All Java Sources">
<property name="myclasspath" refid="project.classpath"/>
<echo message="Classpath = ${myclasspath}"/>
<javac ...>
....
</javac>
</target>
It will print out the classpath used to run the specific target

running specific target in different ant scripts in different directories

We have a large amount of apps. They all have a build.xml file located in the projects base directory. I am trying to create an ant script that will go through and call a specific target on each of the build.xml files in all the projects.
Here are the issues:
Some of the projects are in deeper directories than others.
Only some of the projects need to be built at a time.
I was trying to use subant + antfile and defining a CSV of file paths in a properties file, but this did not work. Below is what i have and the error i am getting.
If there is a better way to do this or you know what my problem is, please let me know! Thanks!
This is the property defined in a property file. I am wanting the person running the script to add the file paths in here that are relative to the current location of the script they are running.
projects.to.build=
This is the subant task i am trying to use in the main build script.
<filelist
id="projectNames"
dir="${basedir}"
files="${projects.to.build}"
/>
<target name="debugAll" description="Builds all the projects listed in the projectNames.properties file.">
<subant target="debug" antfile="${projects.to.build}">
</subant>
</target>
Here is the error i get when i try to run the build script when there are projects defined in the properties file. I am using the relative path. For example: ..\Apps\AnApp1\build.xml,..\Apps\AnApp2\build.xml,..\OtherApps\foo\AnotherApp1\build.xml
"No Build Path Specified" (at my subant task)
You specified the antfile attribute, so ANT was expecting to a single build.xml file.
The subant documentation describes how you can use a fileset as child parameter.
Here's an example:
<project name="Subant demo" default="run-debug-target">
<target name="run-debug-target">
<subant target="debug">
<fileset dir="." includes="**/build.xml" excludes="build.xml"/>
</subant>
</target>
</project>
Update
Alternatively a filelist could be used:
<project name="Dry run" default="run">
<target name="run">
<subant target="test">
<filelist dir="projects" files="one/build.xml,two/build.xml,three/build.xml,four/build.xml"/>
</subant>
</target>
</project>
Processing the following build files:
projects/one/build.xml
projects/two/build.xml
projects/three/build.xml
projects/four/build.xml
Is it possible to run the target in the all the build files concurrently ?
E.g.
<project name="Dry run" default="run">
<target name="run">
<subant target="test">
<filelist dir="projects" files="one/build.xml,two/build.xml,three/build.xml,four/build.xml"/>
</subant>
</target>
</project>
In this example, is there any way to run target "test" present in all the build files (one/build.xml,two/build.xml,three/build.xml,four/build.xml) concurrently ?

How do I pass an argument to an Ant task?

I'm not very good with Ant, but we're using it as a build tool. Right now, we can run "ant test" and it'll run through all the unit tests.
However, I'd love to be able to do something like ant test some_module and have it accept some_module as a parameter, and only test that.
I haven't been able to find how to pass command line args to Ant - any ideas?
One solution might be as follows. (I have a project that does this.)
Have a separate target similar to test with a fileset that restricts the test to one class only. Then pass the name of that class using -D at the ant command line:
ant -Dtest.module=MyClassUnderTest single_test
In the build.xml (highly reduced):
<target name="single_test" depends="compile" description="Run one unit test">
<junit>
<batchtest>
<fileset dir="${test.dir}" includes="**/${test.module}.class" />
</batchtest>
</junit>
</target>
You can also define a property with an optional default value that can be replaced via command line, e.g.
<target name="test">
<property name="moduleName" value="default-module" />
<echo message="Testing Module: ${moduleName}"/>
....
</target>
and run it as:
ant test -DmoduleName=ModuleX
What about using some conditional in your test target and the specifying -Dcondition=true?
<target name="test" depends="_test, _test_if_true>
...
</target>
<target name="_test_if_true" if="condition">
...
</target>
<target name="_test" unless="condition">
...
</target>
Adapted a bit from the ant faq.
You can define a property on commandline when invoking ant:
ant -Dtest.module=mymodulename
Then you can use it as any other ant property:
...
<fileset dir="${test.dir}" includes="**/${test.module}.class" />
...
Have a look at Ant's manual.
I tried the solutions posted here for the very same original question. Yes just use ant -D<arg_name>. THe -D is a "keyword" I guess. I'm no ant expert and have not read the manuals in detail. Then inside the ant XML files can be accessed like: ${arg_name}
For instance you can have an argument name like: arg.myarg, so in XML ${arg.myarg}.
Ant really doesn't have parameters_ for the build file. I can think of a few ways to do this:
Use a special target to specify the tests. You can use the <for/> task from AntContrib to allow you to specify multiple tests. You'll need to download the Ant-Contrib jar file. I recommend placing it inside your project under the `${basedir}/antlib/antcontrib" directory. That way, when others checkout your project, they get the needed Ant-Contrib jar file.
<property name="antlib.dir" value="${basedir}/antlib"/>
<property name="antcontrib.dir" value="${antlib}/antcontrib"/>
<!-- Set up the ant contrib tasks for your use -->
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<fileset dir="${antcontrib.dir}"/>
</classpath>
</taskdef>
<target name="select-test"
description="Select the tests to run"
depends="test-compile"
if="junit-tests">
<for parameter="module"
list="${junit-tests}"
delimiter=" ">
<sequential>
<junit
fork="true"
...>
<batchtest todir="$target/unit-tests">
<fileset dir="${test.destdir}">
<include name="**/#{module}.class"/>
</fileset>
</junit>
</sequential>
</for>
</target>
You cab now run multiple tests like this:
$ ant -D"test-one test-two test-three" select-test
You could try this to access one target at a time. Add these lines to your build.xml file :
<project name="whatever" default="default">
<input message="Please select module:" addproperty="mod" />
<target name="default" depends="${mod}/>
...
</project>
This allows you to enter the module you want to execute and execute that itself instead of running the whole build.xml
You might need to make a few more changes to your build.xml for this to work perfectly.
For the arguments , there is Facility called property. You need to set the property. As in ANT plain arguments is taken as target name.
Lest say you have two modules in your project ModuleX and ModuleY where ModuleX has 2 testcases to run and ModuleY with 10 testcases.
You could do something like this :
ant runTestsOnModule -Dtestmodule="ModuleX"
OR to test all modules by calling
ant tests
<target name="runTestsOnModule">
<antCall target="testcase${testmodule}"/>
</target>'
<! -- run single module -->
<target name="runTestsOnModule">
<antCall target="testcase${testmodule}"/>
</target>
<!--run all tests-->
<target name="tests">
<antcall target="testcaseModuleX">
<antcall target="testCaseModuleY">
</target>
<target name="testcaseModuleX">
..run junit task to call 2 testcase
</target>
<target name="testcaseModuleY">
....run junit task to call 10 testcase
</target>

Resources