May 18, 2009

Maven Plugin Releases: Do it yourself!

In my previous post, I have complained about Maven plugins that do not release new versions although there are blocking issues that are reported in Jira with patches attached to them. If you don't want to wait any longer for a new plugin release, just build one on your own. Here's how we usually do that.

Fix the Plugin

  1. Checkout plugin sources from source repository and import as Eclipse project. The easiest way to do this is to use m2eclipse plugin's cool "Materialize Maven Projects" feature (see here).
  2. Edit the POM and change the plugin's version number (see notes below).
  3. Download the patch from the JIRA issue page.
  4. Appy the patch using Eclipse: in project's context menu, select Team > Apply Patch...
  5. Now build, unit-test and install the plugin using Maven.
  6. Update your project's POM to use this new version, and test, test, test....
  7. If everything is fine, upload your patched plugin to your repository manager to make it available to your team members.
  8. Check in all changes you made, probably including the fixed plugin – into your repository, of course, not the plugin's one!

Give Some Thought to Version Numbers

A few rules on the fixed plugin's version string that have proven rational for us:

  • You should not just increase the version number to prevent mix-up with future official versions of the plugin.
  • Instead, we usually add a suffix made up of our company name and a consecutive number, like "-fja-1" for the first fix. This indicates the initiator and gives room for further fixes in case they should be required. Additionally, you always see the underlying official version. Example: <version>2.5-fja-1</version> for FJA's first fix of version 2.5.
  • Don't change the plugin's group or artifact id because this would bypass Maven's version resolution, i.e. in Maven's eyes your fix would not just be a new version, but another plugin. You possibly end up having both plugins (the original one and your fix) configured in your builds, leading to duplicate execution and unexpected results.
  • If you just change the version string, this can be done in the parent POM – you are locking down your plugins in your corporate/project root POM, do you? – making it easy to switch back to an official relase later... in case there is one available.

May 13, 2009

Maven Compromised by Plugins

Every piece of software has its flaws... The important part is how the project is dealing with bugs.

Maven is fine

With Maven, the situation actually is good enough: there have been releases of 2.0.x branch 1-2 times per year, to fix bugs and provide new features or improvements. At the same time, the 2.1.0 branch appeared with a milestone and a final release six month later.

However, you would usually not want to switch your Maven build system to a new version too often. This is always risky since a new version of the "core" may cause unexpected results in any area of the build. A continuous integration engine helps to detect bugs, but you never know.

Fortunately, Maven is heavily based on plugins – which means if you encounter any issue with a specific Maven task, it's usually caused by the related plugin, not the Maven core. That's great, right? You just upgrade your POMs to use a new version of the particular plugin. Better isolation, fewer risks!

(Some) Plugins are not!

But... this assumes that there is a new version of the plugin available. Now imagine this: a plugin has a bug reported by the community, and there is a Jira issue for that. Some brave soul even attached a patch to fix the issue and others confirmed that it works for them. Thus, the new bugfix release could easily be built. But what happens? No new release. Nothing. Not even an alpha/beta version. Not even a comment explaining why. For months!

Here are just two examples we stumbled upon the last couple of weeks:

  • Javadoc plugin: The report is not generated at all for multi-module project if run from parent level and using the recommended aggregate goal. Jira issue reported 2008/08/18, patch added 2008/09/22. No new release ever since.

  • Checkstyle plugin: Current version does not work with Checkstyle 5.0 that started to appear on the stage last summer. Jira issue created 2008/10/28, along with a patch; another patch added 2009/03/27. No new release ever since.

Wow. How annoying is that? There is a major/blocking issue, and there is a patch available, but the plugin owners don't take the time or effort to create a new release?!? Why so? What else could the community do to help fixing the plugin?

This way, the plugins are compromising usability of Maven. IMHO, that's a serious issue...

So, what can you do?

If you don't want to continue waiting for a new plugin release, you have to build one on your own, for your "private use". That's quite easy, fortunately, and I'll probably post about that later.

However, this is actually not what a typical Maven user wants to do. The plugins should just do it right: release more often to fix their known bugs! You could increase the pressure a little bit by voting for the Jira issue or adding some comments, but my experiences are not too good ...

May 11, 2009

Update to Checkstyle 5.0

Checkstyle 5 is available!

This is good news: a new version of Checkstyle is available that better supports Java 5 language features (like generics, annotations or package-info files). Additionally, some checks are cleaned up a bit, for instance concerning their parent in which they are contained. See the release notes for details.

Due to these changes, Checkstyle 5.0 is not fully compatible to previous versions 4.x – which is already indicated by the version number leap. Hence, don't expect the upgrade to be smoothly!

Nevertheless, I thought it would be time to upgrade, so here is what I did...

Step 1: Upgrade checkfile configuration

Due to the incompatabilities, I had to apply some changes to our checkstyle configuration to make it work with Checkstyle 5. To be sure I did it right, I have downloaded and used the Checkstyle binaries and checked my configuration for just a simple project. Hence, before upgrading Eclipse and Maven Checkstyle integration, I know my configuration is correct.

BTW, we are using a common checkstyle configuration file for all projects, and reference this "global" file with Maven and Eclipse in different ways:

  • With Maven, we use a custom artifact that contains nothing but our checkstyle.xml file. This in turn is included as build extension in our main base POM. See this post for more details.

  • For Eclipse, we use the "Eclipse Checkstyle Plugin" that provides a Remote Configuration option to reference the configuration file on an internal file server.

Step 2: Upgrade Eclipse Plugin

There is a new Beta-Release of Eclipse Checkstyle plugin (eclipse-cs) available on its update site http://eclipse-cs.sf.net/update. At the time of writing, there are three features available:

  • Eclipse Checkstyle Plug-in – version 5.0.0-beta4
  • Eclipse Checkstyle Plug-in 4.4.x -> 5.0.0 Migration (Optional) – version 5.0.0-beta4
  • m2eclipse Maven Synchronization Plugin (Optional/Experimental) – version 0.0.3

Oh, seems there would have been some help in migrating from Checkstyle 4.4 to 5.0... Doesn't matter, I always like to see what the changes are so it's good to do it manually.

The m2eclipse Synchronization plugin is a new feature providing mechanism to synchronize Checkstyle rules and configuration between the maven plugin and eclipse-cs. Sounds really interesting... but let's do one step after the other and test this later.

So. I just installed the "Eclipse Checkstyle Plug-in" feature. Eclipse didn't recognize that this actually is an update, so you have to uninstall the previous eclipse-cs installation manually.

Why that? Well, the "package" has changed from com.atlassw.tools.* to net.sf.eclipsecs.*, and this applies to the feature's ID, too. Moreover, this renaming also affects the buildCommand and nature in .project files, they have to be net.sf.eclipsecs.core.CheckstyleBuilder and
net.sf.eclipsecs.core.CheckstyleNature
now.

Additionally, the notation for file sets has been changed: a file set previously configured as src\\main\\java\\com\\mycompany\\.* does no more match to any file; instead, it has to be the slash now like in src/main/java/com/mycompany/.*.

Okay, maybe I should have tried the Migration plugin... Anyways, after these changes everything works fine for me in Eclipse.

Step 3: Upgrade Maven Plugin

Good. Last piece is Maven, which provides the Maven 2 Checkstyle Plugin. However, the current version is 2.2 which is based on Checkstyle 4.4 by defining these dependencies:

<dependency>
<groupId>checkstyle</groupId>
<artifactId>checkstyle</artifactId>
<version>4.4</version>
</dependency>
<dependency>
<groupId>checkstyle</groupId>
<artifactId>checkstyle-optional</artifactId>
<version>4.4</version>
</dependency>
There is an interesting way to override the plugin's dependencies pointed out by Brian Fox, but that's not going to work for us because Checkstyle versions 4.4 and 5.0 are not API compatible.

What can we do? Not much... we'll have to wait for a new version of the Checkstyle plugin that updates to Checkstyle 5. There is this Jira issue, and patches have already been provided some time ago. It's only that there seems to be no progress whatsoever... Checkstyle 5.0 is officially out since April 18th, so there is no reason to wait any longer! Create a new release (for my part, alpha/beta is fine as well) – please!!!

If you really need the plugin to be fixed now, you could checkout the plugin's sources and built your own version, applying the patch provided in the Jira issue. That works, but is nothing we want to do regularly!

May 5, 2009

Eclipse: Update Manager Fools Me

Recently, we experienced an issue with a custom Eclipse plugin developed and hosted by my company. When trying to install the plugin into various versions of Eclipse Ganymede, the update manager always told me "Cannot find a solution satisfying the following requirements org.eclipse.ui [3.4.2.M20090204-0800]".

Finally, after some lost days of searching and trying, we discovered that this message is totally misleading: the issue was not caused by the feature org.eclipse.ui missing or being available only with wrong version. Instead, the reason was a misconfigured Manifest file of the custom plugin. It just defined wrong version for the required bundles (oAW, the MDA/MDD generator framework we use).

How nasty is that? Couldn't Eclipse update manager (p2) provide better support? More useful messages? Gosh!

Moreover, Eclipse update manager seems to cache the metadata of remote repositories. That might be nice to avoid network overhead of loading the repository again and again. But... when testing installation of different plugin versions with a local update site, it definitely gets into your way. The sad thing is, you can't get rid of the cached contents easily. You'd have to remove the site, restart Eclipse with -clean option two times, and after that recreate the location. Could be made easier, really.

Eclipse update manager will once more be refactored in upcoming Eclipse 3.5 Galileo. Folks, don't mess it up again!

May 4, 2009

Maven Enforcer Plugin: cool and annoying

As a Maven expert, you probably have heard of maven-enforcer-plugin, "The Loving Iron Fist of Maven", as they say.

It's so cool!

The idea is pretty cool: the plugin provides goals to ensure that the environment used to run Maven is like you – the POM author – expected it to be. There are checks for constraints on the version of Maven or JDK, on the OS family, to enforce certain dependency requirements, and much more. This list on the web site gives you an impression on what kind of checks are provided.

Do you know what happens when you write your POMs and settings for Maven version 2.0.9 or greater, but somebody is still using an outdated 2.0.4? Well, this kind of issues is annoying and you better make sure it does not happen.

The current version of maven-enforcer-plugin (at the time we set it up) was 1.0-alpha-4 which sounded not very mature, but nevertheless we decided to use it. For our projects, we identified a couple of things we wanted to check, and we configured the plugin accordingly:

  • Java Version: should be 1.5.
  • Maven version: must at least be 2.1.0.
  • Enforce defined versions for all plugins, and disallow any use of "LATEST", "RELEASE" or "SNAPSHOT" as a version for any plugin.

Hey, SNAPSHOT plugins are just dangerous and you should never, never ever depend on them. The only exclusion could be plugins developed inhouse, but actually, no – not really. Bah, don't use SNAPSHOT plugins. Period.

So, we tried to setup our enforcer plugin configuration like this:

<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.0-alpha-4</version>
<executions>
<execution>
<id>enforce-versions</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireMavenVersion>
<version>[2.1.0,)</version>
</requireMavenVersion>
<requireJavaVersion>
<version>1.5</version>
</requireJavaVersion>
<requirePluginVersions>
<message>Best Practice is to always define plugin versions!</message>
<banLatest>true</banLatest>
<banRelease>true</banRelease>
<banSnapshots>true</banSnapshots>
</requirePluginVersions>
</rules>
</configuration>
</execution>
</executions>
</plugin>
Of course, we wanted to apply the same checks on command line as within Eclipse when using m2eclipse plugin.

It's so annoying!

Well, and here is where the trouble started...

Shot one. Oh, wait, we are using Maven version 2.1.0-M1 currently. Guess what? This is not included in range [2.1.0,) which means every version x >= 2.1.0. Okay. Let's use [2.1.0-M1,) instead.

Shot two. What about Eclipse? The check fails within Eclipse, and it turns out that the version number reported by the Maven embedder used by m2eclipse (0.96 at that time) is 2.1-SNAPSHOT. Thus, enforcer fails and we'll have to use this for the Maven version specification:

<version>[2.1.0-M1,),[2.1-SNAPSHOT,)</version>

Ugly, but still manageable...

Shot three. My team reported the enforcer plugin to sometimes use some "thinking time" when checking the environment – it seems to hang for couple of seconds. We all see that betimes, and I have no idea what it is caused by. Actually, performing those version checks should be fast as light, right?

What makes this even worse is the fact that in multi-module builds, enforcer plugin is called for each subproject. It binds by default to the validate lifecycle phase which is executed for every subproject. However, the environment does not change very much during a single build, so it would be sufficient to check that only once per Maven call...

Shot four. When establishing the cool Sonar quality management platform, Maven started to complain that "some plugins are missing valid versions". Seems that Sonar defines dependencies to other artifacts used internally, but doesn't give a version for them. All you can do is specify a version for those plugins in the <pluginManagement> section of one of your parent POMs. That's actually not what you want: explicitely list versions for artifacts used internally by the current version of a build tool... But what else can you do? Completely disable the requirePluginVersions check?

Shot five. After upgrading m2eclipse to version 0.97, it does not correctly handle our enforcer configuration any more and instead yields an error:

org.apache.maven.lifecycle.LifecycleExecutionException: Invalid or missing parameters: [Mojo parameter [name: 'rules'; alias: 'null']] for mojo: org.apache.maven.plugins:maven-enforcer-plugin:1.0-alpha-4:enforce

This is a known issue, and you have to uncheck the "Skip Maven compiler plugin when processing resources" checkbox in the project's properties. That means, we have to change configuration for all our projects :-(

Moreover, it was the default to check this option and it seems to have negative performance impact when deselected.

Game over. This is the point where we eliminated enforcer plugin. Too much pain for a little helper tool. One of those things that seems to be quite cool at first glance, but starts to annoy you very soon.