Maven: multi-project and dashboard issues
Some Maven multiproject experiences will be described in this post. Special attention is paid to the dashboard plug-in.
Maven: multi-project and dashboard issues
Generic Maven project structure
Let us first reiterate the canonical structure of a Maven
(sub)project:

This project structure will henceforth implicitly be assumed for
all subprojects constituting an overall superproject.
A canonical multiproject lay-out
Although most if not all plug-ins work flawlessly with the
multiproject structure as outlined below, it is not a universally
applicable lay-out. For example, this lay-out does’t integrate
well with the Eclipse or WSAD IDEs.
However, for a proper understanding, let us first shortly
(re)introduce the canonical multiproject structure, that is
(sometimes implicitly) assumed in most Maven and
Maven plug-in related documentation.
Canonical multiproject structure
The lay-out of a canonical multiproject project is as follows
(where we collapsed the subproject tree structure as was listed
above):

Invoking
$ maven multiproject:site
a target directory is generated containing the maven generated
site.
The advantage is that set aside some customizations and/or
optimizations, a maven.xml is not needed, hence
your Maven (and Jelly) related knowledge can be restricted
to the bare minimum. Moreover, you project structure lay-out
will be Maven generic!
Below we will focus a bit more on the precise contents of
the project.xml and the project.properties,
in order to be able to point out the differences with our
more generalized case that will be discussed thereafter.
Contents project.xml
An example project.xml has been listed below.
We made use of the possibility to inherit (extend) from a top-level
project.xml file, located in one of the subprojects.
This is especially usefull when dealing with a project consisting
of a lot of subprojects and is almost always employed.
This project.xml is responsible for the main (overview)
project site. The dashboard and multiproject plug-ins are configured
here, the former generating a summary of project metrics
(which metrics are to be included can be configured, see
the project.properties below),
the latter analyzing the version convergency of the
dependencies of all subprojects on (external) artifacts,
such as JAR and ZIP files.
Of course, other plug-ins, such as the mutlichanges plug-in can
and may be configured here as well, but we will refrain from
doing so for the sake of clarity.
A template project.xml is shown below:
<?xml version="1.0" encoding="UTF-8"?>
<project>
<extend>sub-project-m/top-level-project.xml</extend>
<pomVersion>3</pomVersion>
<id>site</id>
<name>Overall Site</name>
<reports>
<report>maven-dashboard-plugin</report>
<report>maven-multiproject-plugin</report>
</reports>
</project>
Contents project.properties
Below we have only listed those properties
from the project.properties file that are relevant
to the multi-project plug-in (and reactor) and the
dashboard plug-in and associated overall report generation:
#
# Multiproject
#
maven.mutliproject.basedir=.
maven.multiproject.includes=sub-project-*/project.xml
maven.multiproject.excludes=sub-project-DontBuildMe
#
# Dashboard properties
#
# Tells the dashboard plugin not to run its own reactor.
# We’ll use the one run by the multiproject.
maven.dashboard.runreactor = false
#
# Tells the multiproject plugin to execute the dashboard:report-single
# goal on each project when you run it through multiproject:site.
maven.multiproject.site.goals=site, dashboard:report-single
#
maven.dashboard.aggregators = csfiles,cswarnings,cserrors,junittests,junitfailures,juniterrors,junitpassrate,pmdfiles,pmdviolations,simiantdl,jcoveragelipc,jcoverageloc
The multiproject related properties don’t need to be explained,
except maybe for the maven.multiproject.excludes: this
property is optional and can be used for those subprojects that must
(temporarily) be exempted from the build process.
Dashborad report generation
It turns out that the dashboard plug-in seamlessly integrates
with this canonical multiproject structure. An integrated
summary will be available under the project report section.
An example of such a summary is listed on the Dashboard plug-in page,
http://maven.apache.org/reference/plugins/dashboard/.
Of course, for those subprojects that have dashboard reporting
enabled in the report section of their POM (project.xml),
a dashboard report for the subproject itself is included in the
project reports section.
Multiproject with root subproject
The need for a more generalized lay-out has been motivated at the
beginning of this document. In practice, this "root"
subproject may be named differently, such as main project, site
project or deployment project.
Multiproject with root dir structure
The lay-out of a canonical multiproject project that contains
a root project on the same level as the subprojects is depicted
below:

The differences with the canonical case are immediately obvious:
- The
project.xmland
project.propertieshave moved to the root
subproject - A
maven.xmlis mandatory now - The root project is on the same level as the subprojects
- Site pages reside in the
sitedir.
All these small differences imply many small intricate mutations
as compared to the canonical case. These changes will be
elaborated on below.
Contents maven.xml
Let us first focus on the maven.xml file.
<goal name="myProject:site"
description="Build site for the master project and all subprojects">
<echo message="+-----------------------------------------------+"/>
<echo message="| First building sites of separate sub projects |"/>
<echo message="+-----------------------------------------------+"/>
<maven:reactor
basedir="${basedir}/.."
includes="${maven.multiproject.includes}"
excludes="${maven.multiproject.excludes}"
goals="dashboard:report-single, dashboard:report, xdoc"
banner="Build site for subproject "
postProcessing="true"
ignoreFailures="true"/>
<echo message="+----------------------------------+"/>
<echo message="| Performing dashboard aggragation |"/>
<echo message="+----------------------------------+"/>
<attainGoal name="dashboard:aggregate"/>
<attainGoal name="myProject:mainSite"/>
</goal>
<goal name="myProject:mainSite"
description="Build main (root/overview) pages">
<echo message="+-------------------------------------+"/>
<echo message="| Building main (root/overview) pages |"/>
<echo message="+-------------------------------------+"/>
<maven:reactor
basedir="${basedir}"
includes="site/project.xml"
goals="allSite"
banner="Build site for myProject using "
postProcessing="false"
ignoreFailures="true"/>
<echo message="+-----------------------------------+"/>
<echo message="| Copying all to target destination |"/>
<echo message="+-----------------------------------+"/>
<copy todir="${basedir}/target">
<fileset dir="${basedir}/site/target">
<include name="**/*" />
</fileset>
</copy>
</goal>
The maven.xml is composed as follows:
- The
myProject:sitebuilds the whole
site, i.e. the main site and of all subprojects. - It starts off by invocation of the reactor (standard)
for the site generation of all subprojects. - Note the goals that are invoked for each separate subproject!
This is essential to get the dashboard reports
right. - Thereafter, an aggregate dashboard report is generated.
- The overall site is generated. This will require a
section by itself. Note how the generation of the
main site is "handed over" to the
allSitegoal of themaven.xml
in thesitedirectory. - All files are copied to the
target
directory in the root level project directory.
Needless to say, any destination will do, as well as a
deploy to web server, of course.
Contents project.properties
Below we have only listed those properties
from the project.properties file that are relevant
to the project lay-out (and dashboard report generation):
#
# Multiproject
#
maven.multiproject.basedir=..
maven.multiproject.includes=sub-project-*/project.xml
maven.multiproject.excludes=sub-project-root/project.xml
#
# Dashboard properties
#
# Tells the dashboard plugin not to run its own reactor.
# We’ll use the one run by the multiproject.
maven.dashboard.runreactor = false
#
maven.dashboard.aggregators = csfiles,cswarnings,cserrors,junittests,junitfailures,juniterrors,junitpassrate,pmdfiles,pmdviolations,simiantdl,jcoveragelipc,jcoverageloc,javancssncsstotal,javancssjavadocstotal
The properties and their values should be obvious from inspection.
Notice the dashboard relevant properties especially: not more, not
less is needed.
Finally, for dashboard to work properly, you must
incorporate the following lines in the
project.properties of each of the
subprojects:
maven.dashboard.rungoals=true maven.dashboard.includes=project.xml
Overall site generation
The site pages, as well as the overview of all the subprojects
and the aggregate dashboard report are generated based on
the material residing in the site
directory. Rationale: since we deviated from the canonical
project lay-out, the multiproject nor the dashboard plug-ins
"know" how to handle this situation, and special
adaptations have been incorporated to cope with this new situation.
Let us first focus on the overview of all subprojects.
This page is generated from the projects-overview.xml
file in the xdocs-templates directory:
<?xml version="1.0"?>
<document>
<properties>
<title>Overview of projects</title>
</properties>
<body>
<section name="Overview of projects">
<table>
#foreach ($reactorProject in $reactorProjects)
<tr>
<td><b><a href="${reactorProject.file.parentFile.name}/index.html">${reactorProject.artifactId}</a></b></td>
<td>${reactorProject.shortDescription}</td>
</tr>
#end
</table>
</section>
</body>
</document>
Using velocity, this template is transformed into a
projects-overview.xml in the xdocs
directory, which in turn is transformed into an HTML document
by the xdoc plug-in.
This transformation process is controlled by the
maven.xml in the site directory:
<project
default="allSite"
xmlns:j="jelly:core"
xmlns:maven="jelly:maven"
xmlns:x="jelly:xml"
xmlns:u="jelly:util"
xmlns:a="jelly:ant"
xmlns:velocity="jelly:org.apache.commons.jelly.tags.velocity.VelocityTagLibrary">
<goal name="allSite">
<attainGoal name="subSite"/>
<attainGoal name="dashboard:xdoc"/>
<attainGoal name="site"/>
</goal>
<goal name="subSite"
description="Build the overview for all subprojects"
>
<maven:reactor
basedir="${basedir}/../.."
includes="${maven.multiproject.includes}"
excludes="${maven.multiproject.excludes}"
goals="pom"
sort="true"
banner="Building subprojects overview"
postProcessing="true"
ignoreFailures="false"/>
<attainGoal name="dashboard:aggregate"/>
<!--
|
| At this point because 'postProcessing' was turned on we have all
| the processed POMs available to us in the ${reactorProjects} variable.
|
| The overall project page can now be generated.
|
-->
<fileScanner var="templates">
<fileset dir="${basedir}/xdocs-templates">
<include name="*.xml"/>
</fileset>
</fileScanner>
<j:set var="templatesX" value="${templates}X"/>
<j:if test="${!templatesX.equals('X')}">
<j:forEach var="template" items="${templates.iterator()}">
<j:set var="templateName" value="${template.name}"/>
<echo>Processing ${templateName} template ...</echo>
<velocity:merge
name="${basedir}/xdocs/${templateName}"
basedir="${basedir}/xdocs-templates"
template="${templateName}"/>
</j:forEach>
</j:if>
<!--
|
| The sites of the various subprojects are now copied over to the main
| site.
|
-->
<j:forEach var="reactorProject" items="${reactorProjects}">
<echo>Copying target dirs from project ${reactorProject.artifactId} to ${basedir}</echo>
<copy todir="${basedir}/target/docs/${reactorProject.artifactId}">
<fileset dir="${basedir}/../../${reactorProject.artifactId}/target/docs">
<include name="**/*" />
</fileset>
</copy>
</j:forEach>
</goal>
</project>
Note how
- The reactor merely builds the POM, in order to have
all subprojects available, so that we can iterate over
them. With this iteration, the projects overview page
and the dashboard report can be constructed. - The subSite goal generates the overview page
- Where and how the dashboard aggreation takes place
- The dashboard aggregate data (in
dashboard-data.xml) is transformed into
a report (indashboard-report.xml), which
will eventually be transformed into a
dashboard-report.html. - How the site material of the subprojects is copied over
to the overall destination.
In order for the generation of the overview page to
work properly, the following dependencies have to be
incorporated in the project.xml in the
site directory:
<?xml version="1.0" encoding="UTF-8"?>
<project>
<extend>../bibtexml-top-level-project.xml</extend>
<pomVersion>3</pomVersion>
<id>site</id>
<name>BibTeXML Site</name>
<dependencies>
<dependency>
<id>commons-jelly+tags-velocity</id>
<version>SNAPSHOT</version>
</dependency>
<dependency>
<id>velocity</id>
<version>1.3</version>
</dependency>
</dependencies>
<reports>
<report>maven-multiproject-plugin</report>
<!--report>maven-multichanges-plugin</report-->
<!--report>maven-tasklist-plugin</report-->
</reports>
</project>
Moreover, if you want the multiproject convergency report,
you have to enable it here. Do not enable
the dashboard report here: it won’t work, and what’s even
worse, it will overwrite our so carefully aggregated
report with an empty one!
There is a typo at:
#
# Multiproject
#
maven.mu”tli”project.basedir=.
by the way, when i try to keep the master/root project.xml in a dir no subproject is constructed in the end