Configure maven plugin version without changing pom.xml manually - java

Problem Description
I'm working with a collection of old projects from defects4j. My problem now is that since I want to combine those projects with a newer maven plugin, a regression test tool, there are some issue with the maven surefire plugin version.
In the pom.xml that come along with the projects, there are no specifications of surefire version:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>plain</id>
<configuration>
<includes>
<include>**/*Test.java</include>
</includes>
<runOrder>random</runOrder>
</configuration>
</execution>
</executions>
</plugin>
However, the regression tool (made into a maven plugin), require surefire version of 2.14 and above. So I get error like this:
[ERROR] Failed to execute goal edu.illinois:starts-maven-plugin:1.4-SNAPSHOT:select (default-cli) on project commons-lang: Unsupported Surefire version: 2.12.4. Use version 2.13 and above
Efforts Done
I checked several stackoverflow posts, and they talked about the effective pom. When I run mvn help:effective-pom, I can see that the version of surefire used is
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
Question
Since the project collection in defects4j does not specify surefire version in their pom.xml, is there a way to specify the surefire version used to 2.14 or above from command line? I want to prevent from manually editing the pom every time.
Update
by running mvn dependency:resolve-plugins, i get
Plugin Resolved: maven-surefire-plugin-2.12.4.jar
So it seems to me that somehow maven use 2.12.4 as a default. The reason maybe that I used this version previously. How do I fix this?
Without modifying the pom manually?
Any advice will be welcomed!
Update:
Problem solved by editing maven's super pom.

Maven takes the newest version from the repository if there was no version fixed in your POM, parent POM or the super POM (from which every Maven project inherits).
It is best practise to fix a version "manually" in the POM. The best place for this is a parent POM from which the projects inherit (this means, only one place to change).
You cannot just supply a version from command line. Unless you do some tricks like putting <version>${surefire.version}</version> into the plugin definition and set this property from command line.

I'm 4+ years removed from working with poms so don't remember everything, but consider a couple of things.
First, since the pom you show isn't specifying the version of surefire to use I don't think that the 2.12.4 version can be coming from that directly. Try getting a dependency tree to see where things are coming from. Try How can you display the Maven dependency tree for the *plugins* in your project? for that and a few other suggestions.
Second, I think I recall that in your own pom you should be able to specify the version of plugin to associate with a dependency that doesn't specify one. You'll have to research that option yourself.
I think your best bet is the dependency tree to find what's using what and where things are coming from. If you get the tree and still can't figure out what to do try adding the tree output to your question. (You can edit out parts that are proprietary, or clearly unrelated.)

Related

Why is Maven including multiple versions of the same dependency?

I have a Maven java web app (.WAR) project that includes several libraries, including the Wicket libraries (but I don't think the problem is wicket itself, but rather with maven).
Here's the problem: even tho I only include Wicket 6.20.0, the resulting .WAR contains two copies of the Wicket libraries: 6.20.0 and 6.18.0, as you can see in this screenshot:
Thinking of some conflicting imports I printed the dependency tree using the:
mvn dependency:tree
commnad... but there is no mention of Wicket 6.18.0 in the dependency tree! I also double-checked using Eclipse's "dependency hierarchy" view and I can confirm there's no trace of that import.
I even did a search for string "6.18.0" across the entire workspace with Eclipse, but it's nowhere to be found!
How can I find out what is causing the inclusion of that duplicate version of the library?
Maven doesn't work in this way.
The resolution of more than one dependency with the same artifactId and groupId but with a different version will result to a single dependency (the version used is no determinist).
The presence of two artifacts with the same artifactId and groupId but with two distinct versions in a same lib folder of the WAR is probably related to one of these :
you don't execute mvn clean package but only mvn package.
your use a bugged version of the Maven war plugin. Try to update it to check that.
you have a Maven plugin that copies Wicket jars 6.18.0 in the WEB-INF/lib folder of the target folder during the build of the component.
the maven WAR project you are building has as dependency an artifact of type WAR. In this case, the dependencies of the WAR dependency are so overlaid in the WAR project that you are building.
An interesting Maven issue about duplicated JAR because of WAR dependencies :
JARs with different versions can be in WEB-INF/lib with war as dependencies
Your answer and your comment indicate that actually you have a WAR dependency in your build.
Unfortunately, there is not really a good and long term effective solution to bypass this limitation.
As said in my comment, using the packagingExcludes property of the maven war plugin is a valid workaround for the actual issue :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<!-- ... -->
<packagingExcludes>WEB-INF/lib/wicket-*-6.18.0.jar</packagingExcludes>
</configuration>
</plugin>
But beware, using that will do your build less robust through the time.
The day where you update the version of the WAR dependency and that in its new version, it pulls again a different version of wicket, you have still a risk to have duplicate jars with two distinct versions in your built WAR.
Using the overlay feature by specifying the overlay element of the maven-war-plugin is generally better as it focuses on the overlay applied for the war dependency. It fixes the problem early.
As a result, you could define to exclude any wicket JARs from the WAR dependency :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<version>2.4</version>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<overlays>
<overlay>
<groupId>com.whatever.youlike</groupId>
<artifactId>myArtifact</artifactId>
<excludes>
<exclude>WEB-INF/lib/wicket-*.jar</exclude>
</excludes>
</overlay>
</overlays>
</configuration>
</plugin>
This way is better but this is still a workaround.
The day where the dependency WAR is updated and that it pulls new dependencies (other than Wicket) that are declared in your actual build but with different versions, you may finish with the same kind of issue.
I think that declaring a dependency on a WAR artifact should be done only as we don't have choice.
As poms and projects refactoring are possible, introducing a common JAR dependency which the two WARs depend on and that contains only common sources and resources for the two WARs makes really things simpler.
Well, I figured it out while poking around.
I had a dependency of type "war" in the project:
<dependency>
<groupId>com.whatever.youlike</groupId>
<artifactId>myArtifact</artifactId>
<version>1.0.7-SNAPSHOT</version>
<type>war</type>
</dependency>
Apparently (I wasn't aware of this, my fault here) these type of dependencies will include themselves in the classpath by copying all libs to the main WAR /libs folder, but these will NOT show app in the dependency tree / dependency hierarchy.
I solved by configuring an explicit exclusion in the WAR plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<!-- ... -->
<packagingExcludes>WEB-INF/lib/wicket-*-6.18.0.jar</packagingExcludes>
</configuration>
</plugin>
Use clean install and the double dependency will probably be gone.
Because other libs can use same libs but different version or you tried different version and didn't make mvn clean
The command mvn dependency:tree is telling you the correct information - what you are looking at here is an eclipse / build issue.
Clear out all the target and build areas in your project. If need be, check it out from source control to a new folder.
Alternatively you can build your project in IntelliJ IDEA, and see if you get the correct dependencies (most likely you will).

How do I create an Eclipse plugin release using Maven and Tycho?

I am building an Eclipse project that consists of a number of plug-ins that are packed together. I have create POM files for each component and a main POM for the project. Something like this:
projectDir\releng\pom.xml <-- Parent project
projectDir\proj1\pom.xml <-- Child project 1
projectDir\proj2\pom.xml <-- Child project 2
My build currently works by calling the parent POM which builds everything. Until now I have been building using 0.0.1-SNAPSHOT as the version of the parent POM, and in each Eclipse plug-in I have 0.0.1.qualifier as the version in the MANIFEST.MF file.
I now want to promote my latest version to 0.1.0. From my understanding, this means that I have to go over ALL of my POM files AND MANIFEST.MF files and upgrade the version in both of them (since while the version is defined in the parent POM, it is referenced in all child POM:s).
Is this the correct way to do this or is there a way to automate the whole process and not make mistakes?
P.S. There is the Maven Release plugin but this won't work with Eclipse.
For the version update step of a relase process, there is the tycho-versions-plugin which knows how to consistently update the POMs and manifests.
Just go to the root of your parent/aggregator module and call
mvn org.eclipse.tycho:tycho-versions-plugin:set-version -DnewVersion="0.1.0"
This will update the version of the parent project and of all child projects with the same/equivalent version as the parent project. In your case, these are all projects because the Eclipse versions 0.0.1.qualifier is considerered equivalent to 0.0.1-SNAPSHOT in Tycho.
For the remaining steps of the release process (tagging, building, pushing tags, etc.) just call the appropriate SCM or Maven commands, e.g. from a script. I haven't tried to use the maven-release-plugin for this (and apparently no-one else has).
Please have a look here: Unleash Maven Plugin - Tycho Releases
The Unleash Maven Plugin is implemented as an alternative to the Maven Release Plugin and has a Tycho feature which should do exactly what you need. Furhtermore it is much more flexible, failure tolerant and has an integrated rollback feature.
I will publish some blog posts soon to promote and explain this plugin.
just some hints on how we implemented it.
It can be done with an extra plugin that does transformation of versions in MANIFEST.MF and *.product files. This plugin needs to be a lifecycle participant. #Component(role = AbstractMavenLifecycleParticipant.class) the reason for this is that is must transform and commit before the release plugin starts to look for modifications. Then it must also to transformation back after the release.
The mojo executor plugin saves a good deal of work since it can call the replacer, buildhelper and scm plugin from inside your plugin.
Another important gotcha is that you need to disable to hard coded clean invocation that tycho does by confguring the release plugin to configure the clean plugin to skip execution.
Hope this helps.
There is a new feature in tycho-1.1.0 (unreleased at the time of this post) that should support what you're trying to do.
If you've configured your pom correctly for standard maven-release + added the dep to tycho 1.1.0, you can customize your build as follows [1]:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
<configuration>
<preparationGoals>org.eclipse.tycho:tycho-versions-plugin:${tycho-version}:update-eclipse-metadata org.apache.maven.plugins:maven-scm-plugin:1.9.5:add org.apache.maven.plugins:maven-scm-plugin:1.9.5:checkin</preparationGoals>
<completionGoals>org.eclipse.tycho:tycho-versions-plugin:${tycho-version}:update-eclipse-metadata org.apache.maven.plugins:maven-scm-plugin:1.9.5:add org.apache.maven.plugins:maven-scm-plugin:1.9.5:checkin</completionGoals>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-scm-plugin</artifactId>
<executions>
<execution>
<id>default-cli</id>
<goals>
<goal>add</goal>
<goal>checkin</goal>
</goals>
<configuration>
<includes>**/META-INF/MANIFEST.MF, **/feature.xml, **/*.product</includes>
<excludes>**/target/**</excludes>
<message>Changing the Eclipse files versions</message>
</configuration>
</execution>
</executions>
</plugin>
[1] This is taken directly from a tutorial that describes this new feature:
https://wiki.eclipse.org/Tycho/Release_Workflow

Running GwtDriver example app

I'm trying to run gwt-driver example project however running the example app does not work:
$mvn jetty:run
However, no plugin found for prefix 'jetty' is thrown. What am I missing?
A Maven plugin is actually just an artifact, so needs to be fully qualified - groupId, artifactId, and version. This means that a goal like jetty:run actually is something like org.mortbay.jetty:maven-jetty-plugin:6.1.26:run.
The 'prefix' mentioned in the error is a way to refer to the plugin without all of that extra detail. The plugin declares a short name that can be used to describe it, so as long as you list the plugin in your pom, maven can look through each plugin and find the one with the matching prefix, and figure out the group and version from there. The version turns out to not be essential (though it is a good idea to list it), as maven will just look for the latest version of that plugin.
In the case of gwt-driver-sample, I just committed a change to the pom.xml file that adds this in the <build><plugins> section:
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
</plugin>
This is enough to tell maven how to find the right plugin when you call mvn jetty:run from the command line.

Maven Plugin for project semantic versioning

I'm looking for a maven plugin that will help me manage version names and codes of every build that is made on our CI environment. Something that will be able to attach a prefix to the main version code or even update it (not changing the pom.xml). For example:
project version: 2.0.1
git/svn revision: 2342334
jar output: name-2.0.1-2342334.jar
maven repo: ../path/to/local/maven/repo/<package path>/2.0.1-2342334/
The main requirements to this plugin are:
Must be in Maven Repository (which means that NO additional setting required to add this plugin in my pom.xml and run maven)
Must not edit the pom, each time it's applied
A configuration file, would be great, so I could manage the versioning process
Must be able to edit the output file metadata (so the version will be applied as if it was written in the pom.xml file in the first place)
So far I found only maven-buildmetadata-pluging but unfortunately it's not in Maven Repo, so I'm stuck. Any help would be great.
Hosting your own maven repository is very easy, using either Nexus or Artifactory. You can also use the Artifactory cloud version (I'm not affiliated with them...) so it may solve your problem. BTW - a simple server with Apache does the trick as well, but with more work..,
Regarding the plugins: If you deploy snapshot applications then each gets its own version based on timestamp.
For releases another option is to run an svn info and put the result (or part of it) into the generated artifact. The information can then be accessed by the code.
If you change the version of your artifact the pom has to reflect the change, cause otherwise it's not reproducible.
If you change something in your build process (like added versions, whatever) it has to be reflected in the pom file. Otherwise you can not reproduce the build process with the same result.
You have written not to change the pom file but maintaining a separate file. So the questions is: Why not using the pom file itself, cause it's intended exactly for that purpose.
Furthermore all informations which you mentioned by the maven-buildmetadata-plugin can be achived by using existing maven plugins (like build-helper-maven-plugin, buildnumber-maven-plugin).
The SCM information can be used by using the buildnumber-maven-plugin which provides information like SCM revision number (SVN or GIT hash).
An on the other hand if you don't like to change your pom file manually you can use either the versions-maven-plugin or the maven-release-plugin which automatically can change informations in your pom file and handle all these things automatically.
To maintain metadata in your producted artifacts you can configure all plugins (like ear, war, jar) etc. more or less like this where the buildNumber is comming from buildnumber-maven-plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
<configuration>
<archive>
<addMavenDescriptor>true</addMavenDescriptor>
<index>true</index>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
<manifestEntries>
<artifactId>${project.artifactId}</artifactId>
<groupId>${project.groupId}</groupId>
<version>${project.version}</version>
<buildNumber>${buildNumber}</buildNumber>
</manifestEntries>
</archive>
</configuration>
</plugin>
And of course if you really like to use Maven you should have to use an repository manager as already mentioned like Artifactory or Nexus which make life easier.
I just would like to add (although the question is 5 years old and already has an accepted answer) that the Buildmetadata Maven Plugin was not available on the Maven Repo at first, but it is now (since late 2013). People who would like to give it a try find the artifact at the following locations :
com.redhat.rcm.maven.plugin:buildmetadata-maven-plugin
de.smartics.maven.plugin:buildmetadata-maven-plugin
Please note that the name has changed from maven-buildmetadata-plugin to buildmetadata-maven-plugin due to naming conventions.
I'm one of the "original" authors of this plugin at smartics. If you would like to use it, you probably would like to use the fork provided by Red Hat. To my knowledge the two versions do not differ very much and they have not been synced since there is just so much other stuff to do and the plugin seems to be feature stable. ;-)
The source code for both versions is also available on GitHub:
release-engineering/buildmetadata-maven-plugin
smartics/buildmetadata-maven-plugin
As already stated, you have to change the version in the pom. One way of doing that, in combination with the release plugin is:
mvn \
se.bjurr.gitchangelog:git-changelog-maven-plugin:VERSION_HERE:semantic-version \
release:prepare release:perform
Using Git Changelog Maven Plugin

How does Maven understand release:prepare command?

I'm trying to create a plugin which would download and install jars from Maven central as system tools. So I want my line to be like
mvn install-plugin:install org.chaschev:cap4j:1.0
similar to Ruby's
gem install capistrano
This plugin would gather all the needed information about the shortcuts to create from the JAR. I.e. this jar would contain a class implementing an installation interface.
How does Maven understand that in order to execute a command like release:prepare it requires to download the release plugin and to run it? Any better/other way to do this?
Do you mean how the relation between plugin/goal in the comamnd line and plugin implementation is defined? Then the answer is plugin.xml. See plugin.xml for release plugin, e.g. maven-release-plugin-2.0.jar:
<goalPrefix>release</goalPrefix>
...
<mojos>
<mojo>
<goal>help</goal>
...
<mojo>
<goal>prepare</goal>
...
Or do you mean, how Maven discovers which plugins are available? Then the answer is:
There are two default groups where plugins are searched, org.apache.maven.plugins and org.codehaus.mojo
For your own plugin you may want to use name ${prefix}-maven-plugin, e.g. cap4j-maven-plugin
You can keep your name cap4j, but then put the plugin description to your POM, under <plugins>
If you want your build to work at other machines, they should point <pluginRepositories> in POM or in settings.xml to your plugin repository
It is not good to use default Maven groups for your own project.
Instead, define your own group for your plugin, like this:
<pluginGroups>
<pluginGroup>org.chaschev</pluginGroup>
</pluginGroups>
And rename your plugin from cap4j to cap4j-maven-plugin. Then Maven will discover your plugin without further cahnges in POM.
Alternative, without <pluginGroups>, just put following to your POM:
<plugins>
<plugin>
<groupId>org.chaschev</groupId>
<artifactId>cap4j</artifactId>
<version>...</version>
<configuration>
...
</configuration>
</plugin>
...
</plugins>

Categories