Writing Ant build file for several Jenkins jobs - ant

I'm using Jenkins with Ant plug-in to run PHPUnit/Selenium tests. I'm trying to set up several Jenkins jobs (I've only had one job previously).
Tests for these jobs are in the same GitHub repo, but different folders.
So, I could create different Ant targets in my build.xml, but do I need
separate phpunit.xml files for each job (and if so, how do I specify file names in Ant build script?) Or is there a way to make Ant
distinguish between tests in the same phpunit.xml file? Any other good way to go about this? Any examples would be appreciated.
Ant build file:
<?xml version="1.0" encoding="UTF-8"?>
<project name="MyProject" default="build">
<target name="build" depends="clean,prepare,phpunit"/>
<target name="clean" description="Cleanup build artifacts">
<delete dir="${basedir}/build"/>
</target>
<target name="prepare" description="Make log and coverage directories">
<mkdir dir="${basedir}/build/logs"/>
<mkdir dir="${basedir}/build/coverage_selenium"/>
</target>
<target name="phpunit" description="MyTests">
<exec dir="${basedir}" executable="phpunit" failonerror="true"/>
</target>
</project>
phpunit.xml:
<phpunit>
<testsuites>
<testsuite name="MyTests">
<file>path/to/test.php</file>
</testsuite>
</testsuites>
</phpunit>
Thanks!

You can specify the test configuration file using -c or --configuration. The Ant exec task lets you specify arguments for the process you want to run, something like:
<exec dir="${basedir}" executable="phpunit" failonerror="true">
<arg value="-c" />
<arg value="php_unit_1.xml"/>
<exec>

I recommend creating a separate build.xml and phpunit.xml for each project. You can define common targets in a central build-base.xml that you include in each to avoid duplication. Unfortunately, there's no equivalent mechanism for phpunit.xml that I know of.

Related

How can I depend on a parent target from a nested ant project?

Given a build.xml file:
<project name="main" default="build">
<target name="main.init"/>
<extension-point name="init.tasks" depends="main.init"/>
<target name="init" depends="init.tasks"/>
<extension-point name="build.tasks" depends="init"/>
<target name="build" depends="build.tasks"/>
<include file="subsystem1.xml"/>
<include file="subsystem2.xml"/>
</project>
And a subsystemX.xml with something like:
<project name="subsystemX">
<task name="init" extensionOf="init.tasks"/>
<task name="build" depends="init" extensionOf="build.tasks"/>
</project>
I can now say ant build and all subsystems will go through init and build as expected.
However I would also like to be able to say ant subsystem.build and build only that subsystem. The problem is that each subsystem's build depends on all other subsystems' init. In this case however only the subsystem.init will be executed, as ant just looks at subsystem.build's dependencies.
Ideally I would like to add the main init as a dependency to each subsystem's build task, but include blindly prepends "subsystem." to every task name and depends entry so that I don't seem to be able to reference anything outside.
How can I make subsystem.build depend on the main init task?
I'm using a workaround:
In build.xml, I add additional targets for each included file:
<target name="subsystem1.global.init" depends="main.init"/>
<target name="subsystem1.all.init" depends="init"/>
<include file="subsystem1.xml" as="subsystem1"/>
<target name="subststem2.global.init" depends="main.init"/>
<target name="subsystem2.all.init" depends="init"/>
<include file="subsystem2.xml" as="subsystem2"/>
Then in subsystemX.xml, I can depend on "global.init" and "all.init", e.g.
<project name="subsystemX">
<task name="init" depends="global.init" extensionOf="init.tasks" />
<task name="build" depends="init, all.init" extensionOf="build.tasks"/>
</project>
As you can see this does not scale well and I'm still hoping to find a better solution.

Ant Script to Automate the build process

I Want to automate the ANT build process for deploying the applicaiton.
I want to write a ANT script which will recurringly should look for the
build.xml files in the folder and run them, if the sub build is failed
it should skip and continue to other script by writing log.
Could any please post the idea which can help or a sample.
RootFolder
|
|-----Folder1
| |
| |--SubFolder1
| | build.xml
| |--SubFolder2
| | build.xml
|-----Folder2
| build.xml
|
|-----Folder3
build.xml
I'd recommend using the subant task
<project name="Subant demo" default="deploy-everything">
<target name="deploy-everything">
<subant>
<fileset dir="." includes="**/build.xml" excludes="build.xml"/>
<target name="clean"/>
<target name="deploy"/>
</subant>
</target>
</project>
This will find all "build.xml" files and call the "clean deploy" targets on each.
While it's neat to automatically pick up the sub folder builds, it rarely works in large projects unless the builds are independent of each other (build order is important).
The following example uses an explicit filelist, instead of a fileset which is unordered:
<project name="Subant demo" default="deploy-everything">
<target name="deploy-everything">
<subant>
<filelist dir=".">
<file name="Folder1/SubFolder1/build.xml"/>
<file name="Folder1/SubFolder2/build.xml"/>
..
</filelist>
<target name="clean"/>
<target name="build"/>
</subant>
</target>
</project>
Finally, the most advanced solution is to use a dependency manager like ivy to declare each module's dependencies in an "ivy.xml" file. Setup properly, this makes each sub module build more stand-alone. To solve the build "everything in only go problem" ivy provides a buildlist task that can automatically determine the correct build order:
<target name="deploy-everything">
<ivy:buildlist reference="build-path">
<fileset dir="." includes="**/build.xml" excludes="build.xml"/>
</ivy:buildlist>
<subant buildpathref="build-path">
<target name="clean"/>
<target name="build"/>
</subant>
</target>
I have solved my problem, thank you all for the reply, I used below technique to handle the situation.
<?xml version="1.0" ?>
<project name="MasterBuildPrj" default="MasterBuild">
<macrodef name="iterate">
<attribute name="target"/>
<sequential>
<subant target="#{target}">
<fileset dir="."
includes="**/build.xml"
excludes="build.xml"/>
</subant>
</sequential>
</macrodef>
<target name="MasterBuild" description="Build all sub projects">
<iterate target="build"/>
</target>
<target name="clean" description="Clean all sub projects">
<iterate target="clean"/>
</target>
</project>

build multiple projects and clean multiple projects in a single build file with ANT

I have a doubt, I made this build file in order to build 3 different projects
<?xml version="1.0" encoding="UTF-8"?>
<project name="Trinity" basedir="." default="buildall">
<target name="project1">
<ant dir="C:/work/project1"/>
</target>
<target name="project2" depends="project1">
<ant dir="C:/work/project2"/>
</target>
<target name="project3" depends="project1, project2">
<ant dir="C:/work/project3"/>
</target>
<target name="buildall" depends="project3"/>
</project>
This is working now. But I wan to also clean the project before doing the build.
In fact I want to acomplish this:
C:/work/project1 ant clean build
C:/work/project2 ant clean build
C:/work/project3 ant clean build
Thanks in advance.
update: Thanks to the quick response from Alex I did a new build.xml file with the following. And I believe is working well, what do you think?.
<?xml version="1.0" encoding="UTF-8"?>
<project name="Trinity" basedir="." default="buildall">
<target name="project1">
<ant dir="C:/work/project1" target="clean"/>
<ant dir="C:/work/project1" target="build"/>
</target>
<target name="project2" depends="project1">
<ant dir="C:/work/project2" target="clean"/>
<ant dir="C:/work/project2" target="build"/>
</target>
<target name="project3" depends="project1, project2">
<ant dir="C:/work/project3" target="clean"/>
<ant dir="C:/work/project3" target="build"/>
</target>
<target name="buildall" depends="project3"/>
</project>
Thanks.
According to the ant task, you can specify the targets of the external ant build files
<ant dir="C:/work/project1" target="clean build">
Edit:
According to the ant documentation:
You can specify multiple targets using nested elements instead of using the target attribute. These will be executed as if Ant had been invoked with a single target whose dependencies are the targets so specified, in the order specified.
So you can list out multiple targets this way:
<ant dir="C:/work/project1">
<target name="clean" />
<target name="build" />
</ant>
Alternatively you can define a new target in the Project1,2,3 build.xml files called cleanBuild which will in turn call clean followed by build if you want to keep it as a single xml element <ant dir="C:/work/project1" target="cleanBuild">

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