Enforce a minimum version of Maven - maven

Is it possible to specify in a POM the minimum version of Maven required to build the project?
We've been wasting lots of time chasing issues from people building our project due to bugs in older versions of Maven that cause large artifacts (>2GB) to be silently truncated. These tend to cause, unsurprisingly, strange and broken behavior in the final product.
Yes, we have stated that 3.2.5 is the minimum version we intend to support, but I'm wondering: Is there a way to ask Maven to bail if the version is less than that? I reckon I can easily write a plugin to do this, but that seems overkill. So, I was hoping there is a simpler way.

You can use the maven-enforcer-plugin and its enforce goal to specify a minimum required Maven version:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.4.1</version>
<executions>
<execution>
<id>enforce-maven</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireMavenVersion>
<version>3.2.5</version>
</requireMavenVersion>
</rules>
</configuration>
</execution>
</executions>
</plugin>
If someone tries to build the project with a Maven version less than 3.2.5, the build will fail.
You can enforce a lot of different rules with this plugin (Java version, OS...); see the complete list on the plugin documentation.

If you only need the maven version the prerequisites should already do the job:
see: https://maven.apache.org/pom.html#Prerequisites
Anything more than that will require the enforcer plugin (see other answer).

Related

Deployment deploys twice or not at all

I managed to build a Maven project in a way that makes the release deploy artifacts either double or not at all.
Since the project uses an abstract parent pom of our company it's a bit hard to post the relevant code, but I'll try.
First things first. The parent pom has the following definition:
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<configuration>
<deployAtEnd>true</deployAtEnd>
</configuration>
</plugin>
With nothing defined in the actual project, the release will fail after these lines:
[INFO] [INFO] Uploaded to our_repo: http://acme.org/nexus/content/repositories/org.acme.project/1.0.0/org.acme.project-1.0.0-sources.jar (14 kB at 3.8 kB/s)
[INFO] [INFO] Uploading to our_repo: http://acme.org/nexus/content/repositories/org.acme.project/1.0.0/org.acme.project-1.0.0-sources.jar
Our repo doesn't like having two release JARs with the same version, so everything fails. The weird part here is that the deployment is NOT at the end. In fact the project build fails halfway through.
However if I copy the above plug-in in the project, the build will print Deploying repo:org.acme.repo:1.0.0 at end at the same position and then not deploy anothing at the end.
But I'm not even sure that's part of the problem. Still I think both builds should work exactly the same no matter where the plug-in definition is.
I found this question, which made me check the maven-source-plugin in the effective pom. However there are no duplicates there:
<plugin>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
<configuration>...</configuration>
</execution>
</executions>
</plugin>
Nothing is defined in the maven-assembly-plugin either, so no JAR is added for deployment (suggested in this question).
It might have to do with us using Java 10 or Maven 3.5.2, though I'm honestly stumped on what to test and where to progress.
How do I fix this mess? (If you'd like more information about the build, just ask. The pom.xml is way to big to share them here.)
Inspired by that question I tried to disable the release profile, and now it works somehow. I'm not able to conjure any kind of explanation for that behavior.
Snippet for removing the release profile:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<configuration>
<useReleaseProfile>false</useReleaseProfile>
</configuration>
</plugin>

How to stop CI builds in Jenkins from accidentally publishing to release repository?

Sometimes, the developers accidentally check in a version in POM without "SNAPSHOT" in it. This builds the Maven project and publishes the artifacts to release repository. How can I avoid this situation? I only want to publish build artifacts to release repository and not a CI build.
I thought about the following- but none of them is an easy one step solution
Writing a pre-commit hook to check if version was checked in without SNAPSHOT by any one other than admin who is allowed to do a release build;
Modify the Jenkins job to see if the build is a CI build; then grep for version and error out if the version is a not a SNAPSHOT version. For this I need to modify 100s of jobs.
A good solution around this is to leverage the Maven Enforcer Plugin.
Update to 1.4.2
Starting with version 1.4.2 (not released yet, see the enhancement request MENFORCER-204), there is a new requireSnapshotVersion rule, which enforces that the project being built has a snapshot version.
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.4.2</version>
<executions>
<execution>
<id>enforce-snapshot</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireSnapshotVersion/>
</rules>
<fail>${fail.if.release}</fail>
</configuration>
</execution>
</executions>
</plugin>
Write a custom rule
Up to version 1.4.1, there is no built-in rule to fail if the current project is a SNAPSHOT version, but we can still use the evaluateBeanshell rule.
The idea is to make the build fail is the version is not a snapshot version by default. And when the current project is in a release, disable that rule.
For that, you can have the following in your POM:
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.4.1</version>
<executions>
<execution>
<id>enforce-beanshell</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<evaluateBeanshell>
<condition>"${project.version}".endsWith("-SNAPSHOT")</condition>
</evaluateBeanshell>
</rules>
<fail>${fail.if.release}</fail>
</configuration>
</execution>
</executions>
</plugin>
What this does is executing a BeanShell script that evaluates the project's version. If it ends with -SNAPSHOT then the rule passes, otherwise, the rule fails and the build ends. Determining whether a version is a snapshot. (The strict rule for snapshots versions are more complicated but this should cover all use cases). Therefore, such a rule will validate that the project being build has a SNAPSHOT version.
Both configurations above declares a Maven property as
<property>
<fail.if.release>true</fail.if.release>
</property>
They will make your build fails when mvn deploy is run on a SNAPSHOT version, making sure no SNAPSHOT are accidently deployed to the release repository.
Then, the rule need to be disabled when a release is performed. For that, we can define a release profile to disable the defined rule:
<profile>
<id>release</id>
<properties>
<fail.if.release>false</fail.if.release>
</properties>
</profile>
and activate that profile on release with
mvn release:prepare release:perform -Darguments="-Prelease"

How to run maven checkstyle plugin on incremental code only

I want to add auto code review feature to our application. Currently we use maven to do builds. I came across maven checkstyle plugin but want this to run it only on incremental code that gets added and not on older one.
Can i achieve this using this plugin? If yes then please provide pointers on how to do it?
Checkstyle plugin has no idea what files are modified or new.
The only way of incrementally adding checkstyle to a project would be using includes configuration, manually putting new files/packages etc. It's a comma separated list of patterns.
<executions>
<execution>
<id>checkstyle-verify</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
<configuration>
<includes>NewClass.java,AnotherClass.java</includes>
</configuration>
</execution>
</executions>

Maven plugin annotations broken

I'm trying to write a Maven plugin, following the documentation. When I try to build I get:
[ERROR] Failed to execute goal
org.apache.maven.plugins:maven-plugin-plugin:2.9:descriptor
(default-descriptor) on project cmake-dependency-plugin: Error
extracting plugin descriptor: 'No mojo definitions were found for
plugin: com.iar:cmake-dependency-plugin.' -> [Help 1]
Google points me to this Jira issue, which, if I read it correctly means that annotations do not work in maven unless a rather cumbersome workaround is employed (which, by the way, did not work for me).
What bothers me more is that it seems to be closed due to some form of Jira-bankruptcy executed by the Maven developers where a bunch of Jira issues have been summarily closed. Since this seems like the primary way to write Maven plugins, I would think that this would be pretty important, but I'm obviously missing something.
Am I misinterpreting the issue, or are maven annotations really broken?
EDIT: This seems to refer to the same problem, but I would be interested to know more details about why such a seemingly central feature can be left broken like this. Aren't Maven annotations used by Maven plugin developers?
First you are using an old maven-plugin-plugin version 2.9 from 2011...I assume you are working with Maven 3.X and so i would recommend to use an up-to-date version like 3.2. and follow the steps described in the JIRA issue.
Furthermore i would recommend to read the documentation about maven-plugin-plugin where clearly stated that starting with version 3.0 you can use annotations.
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<configuration>
<goalPrefix>XYZ</goalPrefix>
</configuration>
<executions>
<execution>
<id>default-descriptor</id>
<goals>
<goal>descriptor</goal>
</goals>
<phase>process-classes</phase>
</execution>
<execution>
<id>help-descriptor</id>
<goals>
<goal>helpmojo</goal>
</goals>
<phase>process-classes</phase>
</execution>
</executions>
</plugin>

maven-plugin-plugin helpmojo breaking change?

I have a Maven plugin which is a year or two old. Recently I noticed that the helpmojo goal of maven-plugin-plugin appears to not be working.
It is working for an older version of the plugin - I'm not sure at which release it stopped working.
By "not working" I mean that the help goal is not correctly generated and is not found when called using mvn <plugin>:help, whilst other goals are found.
HelpMojo.java is created under target/generated-sources/plugin, but no entry appears in the the plugin descriptor, plugin.xml in the final .jar.
Has a bug or breaking change been introduced in a recent version of maven-plugin-plugin or have I changed something which has prevented it from working as a side-effect? (For example, the plugin project is now multi-module.)
The pom.xml config looks like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>3.2</version>
<executions>
<execution>
<id>generated-helpmojo</id>
<goals>
<goal>helpmojo</goal>
</goals>
</execution>
</executions>
</plugin>
The fix was to downgrade to version 3.1

Resources