tags:

views:

368

answers:

3

In our infrastructure, we have lots of little Java projects built by Maven2. Each project has its own pom.xml that ultimately inherits from our one company "master" parent pom.

We've recently started adding small profiles to our parent pom, disabled by default, that, when enabled, execute a single plugin in a conventional manner.

Examples:

  • The 'sources' profile executes the maven-source-plugin to create the jar of project sources.
  • The 'clover' profile executes the maven-clover2-plugin to generate the Clover report. It also embeds our Clover license file so it need not be re-specified in child projects.
  • The 'fitnesse' profile executes the fitnesse-maven-plugin to run the fitnesse tests associated with the project. It contains the fitnesse server host and port and other information that need not be repeated.

This is being used to specify builds in our CI server like:

mvn test -P clover
mvn deploy site-deploy -P fitnesse,sources

and so on.

So far, this seems to provide a convenient composition of optional features.

However, are there any dangers or pitfalls in continuing on with this approach (obvious or otherwise)? Could this type of functionality be better implemented or expressed in another way?

+1  A: 

The problem with this solution is that you may be creating a "pick and choose" model which is a bit un-mavenesque. In the case of the profiles you're describing you're sort of in-between; if each profile produces a decent result by itself you may be ok. The moment you start requiring specific combinations of profiles I think you're heading for troubles.

Individual developers will typically run into consistency issues because they forget which set of profiles should be used for a given scenario. Your mileage may vary, but we had real problems with this. Half your developers will forget the "correct" combinations after only a short time and end up wasting hours on a regular basis because they run the wrong combinations at the wrong time.

The practical problem you'll have with this is that AFAIK there's no way to have a set of "meta" profiles that activate a set of sub-profiles. If there had been a nice way to create an umbrella profile this'd be a really neat feature. Your "fitnesse" and "sources" profiles should really be private, activated by one or more meta-profiles. (You can activate a default set in settings.xml for each developer)

krosenvold
I thought this was Maven-like re: declarative ("-P fitnesse" as opposed to fitnesee:remotecall, etc). The build command is also being specified only once, on the CI server. Lastly, the intention is that these profiles aren't required for a 'successful' build. Would that help prevent problems?
Brian Laframboise
Well yes declarative. But maven also promotes a single way of doing things and a pick-and-choose model is not that. Aren't your users running fitnesse tests locally too ? I know we ended up with 10-15 small profiles to cover all our bases which is too much. It only starts with fitnesse
krosenvold
integrationtest, fitnesse, javadoc, sources, selenium, jetty:run, cobertura, several surefire variations, jspc and probably several I've forgotten. Once you go down that path there's a lot of small plugins you want to configure this way.
krosenvold
But if you promise to use just that one I'll give you a note that says "ok" ;)
krosenvold
I edited the original response a fair bit.
krosenvold
Ha, noted. :-) Clover seemed like a good idea as it could contain the license file. We have lots of plugins in the master pom that run all the time (surefire, etc). As we've never needed an easy way to conditionally turn them off, or configure them abnormally, I haven't put them in separate profiles
Brian Laframboise
As we're just starting to grow our build infrastructure, these optional profiles give us the 'opt-in' flexibility that we need. Not every project has tests, so running Clover all the time doesn't make sense. If you add tests though, Clover should be run in a conventional way.
Brian Laframboise
Thanks for sharing your experience, though. I'm starting to get a better picture of where this might lead us. Perhaps I'll see if I can simulate a 'meta-profile' feature, or perhaps propose it to core Maven.
Brian Laframboise
A: 

You seem slightly suspicious towards that approach, but you're not really sure why - after all, it is quite convenient. Anyway, that's what I feel about it: I don't really know why, but it seems somewhat odd.

Let's consider these two questions: a) what are profiles meant for? b) what are the alternative approaches we should should compare your approach with?

Regarding a), I think profiles are meant for different build or execution environments. You may depend on locally installed software, where you would use a profile to define the path to the executable in the respective environments. Or you may have profiles for different runtime configurations, such as "development", "test", "production". More about this is found on http://maven.apache.org/guides/mini/guide-building-for-different-environments.html and http://maven.apache.org/guides/introduction/introduction-to-profiles.html.

As for b), ideas that come to my head:

  1. triggering the plug-ins with command line properties. Such as mvn -Dfitnesse=true deploy. Like the well known -DdownloadSources=true for the eclipse plugin, or -Dmaven.test.skip=true for surefire. But that would require the plugin to have a flag to trigger the execution. Not all the plug-ins you need might have that.
  2. Calling the goals explicitly. You can call several goals on one command line, like "mvn clean package war:exploded". When fitnesse is executed automatically (using the respective profile), it means its execution is bound to a lifecycle phase. That is, whenever that phase in the lifecycle is reached, the plugin is executed. Rather than binding plugin executions to lifecycle phases, you should be able to include the plugin, but only execute it when it is called explicitly. So your call would look like "mvn fitnesse:run source:jar deploy".

The answer to question a) might explain the "oddness". It is just not what profiles are meant for.

Therefore, I think alternative 2 could actually be a better approach. Using profiles might become problematic when "real" profiles for different execution or build environments come into play. You would end up with a possibly confusing mixture of profiles, where profiles mean very different things (e.g. "test" would denote an environment while "fitnesse" would denote a goal). If you would just call the goals explicitly, I think that would be very clear and flexible. Remembering the plugin/goal names should not be more difficult that remembering the profile names.

lutzh
Good point about plugins being bound to a lifecycle phase. That might actually be causing problems now (hrmm...)
Brian Laframboise
About direct plugin invocation, what about associated configuration? I don't want to seemvn fitnesse:remotecall -Dfitnesee.port=12345in all our of fitnesse-related projects, should the port change.Can I get the best of both worlds (config values inherited, but only referenced when needed)?
Brian Laframboise
I think configuration is independent of execution, that is, you can still configure it when it is not attached to a build cycle phase.You can just configure it once, though, if you have multiple exectutions, they would have to have the same configuration.
lutzh
Some plug-ins might be attached to a phase by default. I don't know if you can "detach" them, that might be a problem. You might have to define your own packaging. You should be able to see what is executed in your build withmvn help:describe -Dcmd=deploy
lutzh
@lutzh, you can have a configuration per execution, see
Rich Seller
oops, missed out the link: http://maven.apache.org/guides/mini/guide-configuring-plugins.html#Using_the_executions_Tag
Rich Seller
+1  A: 

There isn't a problem with having multiple profiles in Maven, in fact I think they are an excellent way of allowing your build to enable and disable classes of functionality. I'd recommend naming them based on their function rather than the plugin though, and consider grouping functionally related plugins in the same profile.

As a precedent for you to follow, the Maven super POM has a "release-profile" defined, which includes configurations for the source, javadoc, and deploy plugins.

You should consider following this approach, so your "fitnesse" profile would become "integration-test", and you could choose to define additional plugins in that profile if needed at a later date. Similarly the "clover" profile could be renamed "site", and you could define additional reports in that profile, e.g. configurations for the JDepend, JXR, PMD plugins.

Rich Seller