Context

Currently, plugin versions, if unspecified, resolve to the "latest" from the repository, which (depending on the repositories included) can include snapshots. It also means that builds change change without the POM changing.

In addition to the ones the users specify, several plugins with no version attached are implied by the lifecycle, making it quite cumbersome to specify all the plugins that a build might use in the POM to ensure that the versions are locked down over time.

While this situation is problematic, the alternative of requiring every single plugin version be provided is too cumbersome and verbose a task in many situations - particularly in the case of the implied plugins.

It should also be noted that anything in the Maven installation itself (such as the settings, or in the past the plugin registry) is not an adequate solution - the POM must be the definitive reference for how to build the software and changing Maven installations should have no effect.

Out of Scope

The original discussion also touched on the following, which are related but separate issues:

  • locking down versions at release time where they were not specified (a more general problem, as it includes not only RELEASE/LATEST, but ranges too).
  • separation of "declaration" from "instantiation" for a POM.

Solution

Required Plugin Versions

After implementation, Maven will require the version in plugin definitions that are bound to the lifecycle in the POM from modelVersion 4.1.0+. Plugins will not be resolved to the latest version (except for the CLI exception listed below).

However, in 4.0.0 modelVersions, Maven will continue to allow the RELEASE as the version for backwards compatibility.

Super POM

The Super POM should declare a default version of the clean plugin as a special case. This will not be the case for the site plugin, or standard packaging plugins.

Plugin Packs

The additional requirement to declare all versions is not an inconvenience when the plugin is already declared - just one additional line.

However, for the implied plugins (jar, compile, resources, etc) - this would involve an undesirable amount of boilerplate. To better facilitate this, we should add the concept of plugin packs.

After the releases of one or more included plugins, a pack release can be made that includes the plugins and their versions. This is achieved through the deployment of a POM project that declares a number of plugins - this has the advantage of having the same syntax, as well as easy cut-and-paste if necessary. For example, the Java plugin pack:

<project>
  <groupId>org.apache.maven.plugins.packs</groupId>
  <artifactId>maven-java-plugins</artifactId>
  <version>1.0</version>
  <packaging>pom</packaging>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>2.1</version>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.2</version>
      </plugin>
      ...
    </plugins>
  </build>
  <reporting>
    <plugins>
      ...
    </plugins>
  </reporting>
</project>

To incorporate this into a project:

<project>
  ...
  <packaging>jar</packaging>
  
  <pluginPacks>
    <pluginPack>
      <groupId>org.apache.maven.plugins.packs</groupId>
      <artifactId>maven-java-plugins</artifactId>
      <version>1.0</version>
    </pluginPack>
  </pluginPacks>
  ...
</project>

Only the build and reporting plugins sections of the POM will be incorporated into the project - not the plugin management or other sections such as configuration. In addition, if multiple plugin packs are declared, they should be applied sequentially, overriding any prior.

Note: this facility could later be addressed by mixins in the POM.

Plugin Management

The plugin management section, when declaring a version, must always win over all plugin packs.

A version will not be required in the plugin management section (which can still be used to apply configuration to an already-defined plugin, including those called from the CLI).

CLI

When running a goal from the command line, it should seek the plugin from those defined in the POM (including their versions). If the plugin is not defined in the project at all (or in the case that there is no project, such as with archetype:create), at present the current rules will be retained. It should be a recommended best practice to declare any plugins you use from the command line in the POM that are not once-off goals.

A future enhancement may be to be able to (and if so, require) plugin versions to be declared in the Maven settings files.

Optional: Decouple Packaging Lifecycle Definition

The definition of lifecycles and packaging types currently occurs in the maven-core's components.xml, with others defined in plugins via extensions. With the possible exception of the POM packaging, these can all be moved into the plugins that define the main package goal.

Given this, the user will be required to declare the plugin that contains the packaging (including it's version). Like the earlier requirement, this must not apply to POM's with the previous model version.

Note that a plugin may still contain one or more packaging.

The lifecycle still does not declare plugin versions - this is to be defined in the plugin packs.

Optional: Additional Tooling

It would be beneficial to write a plugin that can look at the current versions in a project, and suggest possible updates available in the repository (and apply them in an interactive fashion). This may suit the maven-pom-plugin.

Votes

+1

 

0

 

-1

jason (in its current form)

  • No labels

1 Comment

  1. A couple notes that you can incorporate from experiences I've had based on a client setup:

    • The enforcer plugin now has a rule to fully lock down all plugin versions
    • You do have to lock down all plugins including things like "eclipse:eclipse" because these are used extensively by many groups and these changing can have serious repercusions in a build environment. Everything must be locked down for it to be stable. So someone can start a new project to try something but when it officially becomes part of the build that must be communicated to the build team and the plugin needs to be locked down. A single point that can vary, let's say the eclipse plugin that has a bug and many people are screwed. It's easy to either use a POM that doesn't have enforcement turned on by not inheriting from the POM with the rule declaration, or an option to turn off enforcement which would always be turned on for blessed builds.
    • Putting all versions in an organization POM is not that loathsome. It's 30 minutes work but it could be easier. I locked down everything with a client including eclipse, idea, and site plugins pretty shortly. It now works great. So in practice this is not that bad.
    • One mixin with a plugin configuration chunk and someone would be done. If we provided a loosely couple set of plugins we think work then people can grab those and put them in their POM. We can have a tool to help them. OBSERVATION: I've noted that build/scm people want to see these versions in an actual file. So being able to grab the recommended set, grab a snippet and check it in. From what I'm seeing the mixins would allow people to put all their version information in one place. A reference to some artifact seems to make people uncomfortable.
    • No versions of anything should be declared in the Super POM. This should be totally externalized.
    • We don't need any new internal mechanism to model this. We can make snippets for people to use, and they will mix and match because they will. We just need to get them started. A snippet inside pluginManagement will do.

    So in short you can effectively do this now using the Enforcer plugin. The fallout of this is we discovered the model is tampered with as Brian had to do some trickery to look at every plugin element accurately as all plugin versions were getting filled in internally when they actually weren't in the POM. With model tampering fixed, and the build plan in place it would be very easy for us to enforce this (it already is but the plugin does and unnecessary dance to achieve this) but it's highly effective.

    Brian has pretty much provided the stability. Cleaning up the internal model, and providing mixins and we have what we need. The lifecycle doesn't need to be refactored for this and we don't need a model for pluginPacks, a simple import will do. Anyone who wants this sort of stability can model this with the trunk version of the enforcer plugin.

    My only objection as it stands:

    • the requirement to refactor the lifecycle for this in particular which I don't think is necessary for this
    • the requirement for a plugin pack notion. I don't think this is necessary.
    • the requirement to hard code anything in the POM. This is definitely a bad thing.