Maven: Let "mvn -Pjenkins" be the same as "mvn clean install pmd:pmd javadoc:aggregate" - maven

We have a number of Maven jobs in our Jenkins instance, each with their own particular invocation string specified in the build configuration similar to
mvn clean install -DDISABLED="javadoc:aggregate" checkstyle:checkstyle pmd:pmd findbugs:findbugs
I would like to consolidate this so that the invocation string is stored somewhere in the POM along with suitable profile information so we can replace the invocation strings of all these slightly different jobs with a
mvn -Pjenkins
standard invocation. To my understanding the defaultGoal entry only supports a single goal which on first glance seems to be insufficient for representing our multiple goals, but might be enough if we can make it correspond to multiple entries instead. If at all possible I would like avoid setting up profile specific bindings to standard lifecycle phases if a simple invocation string will do.

You can configure additional mojos ina profile, and you can bind mojos to life cycle phases. These two things combined will allow you to run additional mojos when a certain profile is given.
This is a standard techniqued used throughout in Maven. For example, when you run "mvn release:perform", it runs a nested Maven session with "-Prelease" that does additional things, such as GPG-signing binaries.
<profile>
<id>jenkins</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>findbugs</goal>
</goals>
</execution>
</executions>
</plugin>
... other mojos ...
The findbugs mojo is bound by default to the compile phase, so this gets invoked automatically at the compilation phase. If you want to use a mojo that doesn't bind to any lifecycle phase by default, you add <phase>...</phase>.
See our POM in the Jenkins core for a complete example where we invoke FindBugs. The other mojos are the basically the same.
Note that for this to work, your default goal needs to invoke the life cycle phase to the certain point (say package or install.)

I don't think there's a direct way to give Maven an invocation string. As you say, you can add a custom 'jenkins' profile in which you configure the checkstyle, pmd, and findbugs plugins to be bound to a build phase (e.g. their default phase). You would still need to run mvn -Pjenkins clean install though. However this has the advantage that you can also add custom config to those plugins (e.g. to include test code in the PMD coverage).

I think you can add the settings for the checkstyle, pmd, findbugs and javadoc plugins in a profile's <build><plugins/></build> section along with a <properties> bit where you can define the javadoc property. Also, add an explicit invocation of the maven-clean-plugin attached to the clean phase. Then just invoke the build like:
mvn -Pjenkins site:site
You could even set the defaultGoal to site, if you like.

Related

how can I validate Maven pom tags? [duplicate]

I have a Maven project that builds fine even though I have specified a completely invalid plugin in my POM:
<build>
<plugins>
<plugin>
<groupId>bla</groupId>
<artifactId>bar</artifactId>
<version>1.9.553342342343</version>
<executions>
<execution>
<phase>compile</phase>
</execution>
</executions>
<configuration>
<project>
<inceptionYear>123123</inceptionYear>
<contributors>
asdad
</contributors>
</project>
</configuration>
</plugin>
</plugins>
</build>
I also don't see any errors in Eclipse and even after deleting the ~.m2\repository folder, it still builds fine. Has something changed in how Maven validates plugins? Or is it first when I declare a goal that it blows up?
Your question raises different matters, namely the different kind of validation checks that are performed by Maven, and when they are actually done. Sit tight, there is a lot to say.
Step 1: Model validation
The first set of validation is done right at the start of the build, when the model of the project is built. This process is done by the Model Builder component, and its goal is to parse the POM file into a Model object (so that later, a full MavenProject object can be created from it, performing notably dependency mediation). This validation step is actually splitted in 2 parts:
A raw model validation, which reasons on the POM, before any inheritance or anything is applied. It looks for missing required values, like the presence of a groupId, an artifactId or a version; that repositories have an id; or, in your case here, that a plugin has a groupId and an artifactId. It doesn't actually check if there is a version, because the version could be inherited, and that wasn't done yet.
An effective model validation, which is performed after inheritance, interpolation and profile/default injection. At this point, the model should be completely valid. Notably, it must have a packaging, each dependency must have a version, each plugin must have a version as well, etc. And the plugin version you have is actually perfectly valid, in the sense that 1.9.553342342343 is technically an accepted version number. In fact, practically all String qualify as a valid version number; the illegal characters are \\/:\"<>|?*. Also, the <configuration> of a plugin is not validated, simply because it can't: that is specific for each plugin, and one could potentially declare a <project> parameter. For the same reason, it doesn't check whether the plugin actually exists in a remote repository, or if any goals, phase, etc. are specified.
Therefore, at the end of this step, that POM is fully validated and perfectly OK.
Step 2: Project building
Then comes the step of actually building the MavenProject from it. Because Maven needs to perform dependency mediation on the dependencies of the project, it first has to download them. So if you have any invalid dependencies (i.e. dependencies that cannot be resolved with the configured remote repositories in the settings or the project itself), that'll stop right here.
But if we imagine that the dependencies are correctly resolved, the build will continue to invoke each plugin one by one. The important point is that plugins, and their respective dependencies, are only resolved if Maven detects that they are going to be invoked during the build. If not, Maven will not try to download anything. Furthermore, the validation of the configuration of the plugin is also done when the plugin is actually invoked and the values are injected into it, to be used by it.
Depending on the Maven command that was launched, not all plugins declared in the POM will have work to do. For example, if phases were entered by the user, like mvn clean package, then every plugin bound to a phase of the clean lifecycle, or the default lifecycle up to package, will be invoked; so any plugin bound to the install phase would not be invoked. Also, if the user entered a goal, like mvn org.apache.maven.plugins:maven-clean-plugin:3.0.0:clean then only that specific goal of that specific plugin will be invoked, and all the other plugins will be ignored.
This last part is why the POM in the question poses absolutely no trouble to Maven, and here are multiple points about it:
It is bound to the compile phase, but it doesn't have a <goal>, so even if that phase were to be executed, there is nothing the plugin could do, since no goals were defined. Maven knows about this, and doesn't try to resolve the plugin artifact.
Let's set a <goal> to foo and re-test, by adding <goals><goal>foo</goal></goals> to the plugin declaration. We have in the POM:
<executions>
<execution>
<phase>compile</phase>
<goals><goal>foo</goal></goals>
</execution>
</executions>
Running mvn clean, or mvn clean validate would still cause absolutely no issue: the compile phase was not executed. But now, if we run mvn compile, we'll finally get an error:
Plugin bla:bar:1.9.553342342343 or one of its dependencies could not be resolved
This is, after all, what we wanted. Since the plugin declaration has a phase of compile, and the command used would run that phase, Maven tries to download it (and fails).
So let's remove the phase. What would happen now?
<executions>
<execution>
<goals><goal>foo</goal></goals>
</execution>
</executions>
Actually, running any command with specific phases, like mvn clean or mvn validate, would now fail the build. The reason is that a plugin can have a default phase (see also the defaultPhase attribute on #Mojo annotated goal). Since each plugin has the discretion of providing a default phase to any of its goal, Maven has to download the plugin artifact, and find out if this particular plugin uses a default. So, our build will fail again, yay!
It's a different story if the user invokes a specific goal. Try mvn clean:clean with the above, and it will not fail. Actually, warnings are just going to get printed that Maven can't resolve the plugin artifact, but none of that is an error, since invoking clean:clean will just invoke the specific clean goal of the maven-clean-plugin. And actually, in theory, there shouldn't be any warnings here; Maven shouldn't try to download anything. It's a side-effect from the fact that using the prefix clean demands to checks to remote repositories in order to resolve it (refer to this answer to know how that works). But if you fully qualify it, without any plugin prefix resolution needed, with mvn org.apache.maven.plugins:maven-clean-plugin:3.0.0:clean, you're back to zero errors/warnings.
Finally, if we remove everything and end up with
<executions>
<execution>
</execution>
</executions>
it should be pretty clear, that nothing you'll do with result in an errors, because in no way can that plugin ever be executed. (You'll still get warnings if using a prefix).
Step 3: Plugin configuration
The last part of the question is the simple one: the configuration validation of the plugin. You'll notice that at no point this was mentioned here; this is because it only happens when the plugin is actually executed. And since it doesn't even exist, it's not likely to be executed.
Let's suppose it is, for the sake of the explanation. Each plugin is configured with a specific configurator. By default, it maps the XML elements to classes, fields, lists, maps, arrays, just like you would expect. You could provide your own configurator, but that's not a trivial task. There is actually no real validation performed: basically, if the configurator can wire the proper values in the mojo, it's done. You can check the different types of converters that are present by default, but it comes down to: not specifying a String "foo" to an expected integer value; passing a correct enumeration name if the plugin expects that; passing proper XML configuration for a custom class (i.e. each field with their own XML element)... Worth pointing out that setting "foo" to an expected boolean property is not a problem, it'll wire false into the value.
And finally, the XML configuration that did not map to any parameter of the mojo are completely ignored, so even if the bar plugin existed and didn't take any parameters, passing a <project> in the XML configuration would just be ignored, and wouldn't cause any errors.

How does plugin validation work in Maven, and why does it build my project with an invalid version?

I have a Maven project that builds fine even though I have specified a completely invalid plugin in my POM:
<build>
<plugins>
<plugin>
<groupId>bla</groupId>
<artifactId>bar</artifactId>
<version>1.9.553342342343</version>
<executions>
<execution>
<phase>compile</phase>
</execution>
</executions>
<configuration>
<project>
<inceptionYear>123123</inceptionYear>
<contributors>
asdad
</contributors>
</project>
</configuration>
</plugin>
</plugins>
</build>
I also don't see any errors in Eclipse and even after deleting the ~.m2\repository folder, it still builds fine. Has something changed in how Maven validates plugins? Or is it first when I declare a goal that it blows up?
Your question raises different matters, namely the different kind of validation checks that are performed by Maven, and when they are actually done. Sit tight, there is a lot to say.
Step 1: Model validation
The first set of validation is done right at the start of the build, when the model of the project is built. This process is done by the Model Builder component, and its goal is to parse the POM file into a Model object (so that later, a full MavenProject object can be created from it, performing notably dependency mediation). This validation step is actually splitted in 2 parts:
A raw model validation, which reasons on the POM, before any inheritance or anything is applied. It looks for missing required values, like the presence of a groupId, an artifactId or a version; that repositories have an id; or, in your case here, that a plugin has a groupId and an artifactId. It doesn't actually check if there is a version, because the version could be inherited, and that wasn't done yet.
An effective model validation, which is performed after inheritance, interpolation and profile/default injection. At this point, the model should be completely valid. Notably, it must have a packaging, each dependency must have a version, each plugin must have a version as well, etc. And the plugin version you have is actually perfectly valid, in the sense that 1.9.553342342343 is technically an accepted version number. In fact, practically all String qualify as a valid version number; the illegal characters are \\/:\"<>|?*. Also, the <configuration> of a plugin is not validated, simply because it can't: that is specific for each plugin, and one could potentially declare a <project> parameter. For the same reason, it doesn't check whether the plugin actually exists in a remote repository, or if any goals, phase, etc. are specified.
Therefore, at the end of this step, that POM is fully validated and perfectly OK.
Step 2: Project building
Then comes the step of actually building the MavenProject from it. Because Maven needs to perform dependency mediation on the dependencies of the project, it first has to download them. So if you have any invalid dependencies (i.e. dependencies that cannot be resolved with the configured remote repositories in the settings or the project itself), that'll stop right here.
But if we imagine that the dependencies are correctly resolved, the build will continue to invoke each plugin one by one. The important point is that plugins, and their respective dependencies, are only resolved if Maven detects that they are going to be invoked during the build. If not, Maven will not try to download anything. Furthermore, the validation of the configuration of the plugin is also done when the plugin is actually invoked and the values are injected into it, to be used by it.
Depending on the Maven command that was launched, not all plugins declared in the POM will have work to do. For example, if phases were entered by the user, like mvn clean package, then every plugin bound to a phase of the clean lifecycle, or the default lifecycle up to package, will be invoked; so any plugin bound to the install phase would not be invoked. Also, if the user entered a goal, like mvn org.apache.maven.plugins:maven-clean-plugin:3.0.0:clean then only that specific goal of that specific plugin will be invoked, and all the other plugins will be ignored.
This last part is why the POM in the question poses absolutely no trouble to Maven, and here are multiple points about it:
It is bound to the compile phase, but it doesn't have a <goal>, so even if that phase were to be executed, there is nothing the plugin could do, since no goals were defined. Maven knows about this, and doesn't try to resolve the plugin artifact.
Let's set a <goal> to foo and re-test, by adding <goals><goal>foo</goal></goals> to the plugin declaration. We have in the POM:
<executions>
<execution>
<phase>compile</phase>
<goals><goal>foo</goal></goals>
</execution>
</executions>
Running mvn clean, or mvn clean validate would still cause absolutely no issue: the compile phase was not executed. But now, if we run mvn compile, we'll finally get an error:
Plugin bla:bar:1.9.553342342343 or one of its dependencies could not be resolved
This is, after all, what we wanted. Since the plugin declaration has a phase of compile, and the command used would run that phase, Maven tries to download it (and fails).
So let's remove the phase. What would happen now?
<executions>
<execution>
<goals><goal>foo</goal></goals>
</execution>
</executions>
Actually, running any command with specific phases, like mvn clean or mvn validate, would now fail the build. The reason is that a plugin can have a default phase (see also the defaultPhase attribute on #Mojo annotated goal). Since each plugin has the discretion of providing a default phase to any of its goal, Maven has to download the plugin artifact, and find out if this particular plugin uses a default. So, our build will fail again, yay!
It's a different story if the user invokes a specific goal. Try mvn clean:clean with the above, and it will not fail. Actually, warnings are just going to get printed that Maven can't resolve the plugin artifact, but none of that is an error, since invoking clean:clean will just invoke the specific clean goal of the maven-clean-plugin. And actually, in theory, there shouldn't be any warnings here; Maven shouldn't try to download anything. It's a side-effect from the fact that using the prefix clean demands to checks to remote repositories in order to resolve it (refer to this answer to know how that works). But if you fully qualify it, without any plugin prefix resolution needed, with mvn org.apache.maven.plugins:maven-clean-plugin:3.0.0:clean, you're back to zero errors/warnings.
Finally, if we remove everything and end up with
<executions>
<execution>
</execution>
</executions>
it should be pretty clear, that nothing you'll do with result in an errors, because in no way can that plugin ever be executed. (You'll still get warnings if using a prefix).
Step 3: Plugin configuration
The last part of the question is the simple one: the configuration validation of the plugin. You'll notice that at no point this was mentioned here; this is because it only happens when the plugin is actually executed. And since it doesn't even exist, it's not likely to be executed.
Let's suppose it is, for the sake of the explanation. Each plugin is configured with a specific configurator. By default, it maps the XML elements to classes, fields, lists, maps, arrays, just like you would expect. You could provide your own configurator, but that's not a trivial task. There is actually no real validation performed: basically, if the configurator can wire the proper values in the mojo, it's done. You can check the different types of converters that are present by default, but it comes down to: not specifying a String "foo" to an expected integer value; passing a correct enumeration name if the plugin expects that; passing proper XML configuration for a custom class (i.e. each field with their own XML element)... Worth pointing out that setting "foo" to an expected boolean property is not a problem, it'll wire false into the value.
And finally, the XML configuration that did not map to any parameter of the mojo are completely ignored, so even if the bar plugin existed and didn't take any parameters, passing a <project> in the XML configuration would just be ignored, and wouldn't cause any errors.

How to disable jar creation in commandline in a maven project?

I have a maven project for which I'm running two separate builds.
In one build I want to save the build time by disabling the jar creation of maven modules in it.(There are 45 maven modules). There is a Maven-Jar-Plugin that is being used to create the jars.
I want to conditionally disable the jar creation at the command line, that is, looking for something similar to -Dskiptests used to skip the unit tests though there is a surefire plugin by default.
The maven-jar-plugin does not provide any skip option.
However, several ways are possible to achieve your requirement.
You may just skip the phase which brings by default (via default mappings) the jar creation, that is, the package phase, and as such simply invoke
mvn clean test
The additional phases would not make sense if you do not create a jar file anyway: package, install, deploy would not have anything to process. Moreover, the additional integration phases may also be impacted depending on your strategy for integration tests, if any.
Alternatively, you can configure your pom as following:
<properties>
<jar.creation>package</jar.creation>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>default-jar</id>
<phase>${jar.creation}</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
As such, the default behavior would still provide a jar creation, while executing maven as following:
mvn clean install -Djar.creation=false
Would instead skip the creation of the jar.
What we are actually doing:
We are re-defining the default execution of the maven-jar-plugin
We are overriding its execution id, as such getting more control over it
We are placing its execution phase binding to a configurable (via property) phase
Default phase (property value) keeps on being package
At command line time you can still change it to any value different than a standard maven phase. That is, -Djar.creation=none would also work.

Maven define goal dependencies, run initialize before versions:set

I'm including a newVersion propery form an external file using:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0-alpha-2</version>
<!-- Read in newVersion.properties instead of newVersion property -->
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>read-project-properties</goal>
</goals>
<configuration>
<files>
<file>${session.executionRootDirectory}/newVersion.properties</file>
</files>
</configuration>
</execution>
</plugin>
I'm also using versions:set to set the new version of the code from a CI build.
This works if I run:
mvn -DBUILD_NUMBER=99 initialize versions:set
IOW, I need to specify the "initialize" goal explicitly or it stops and prompts me for the newVersion because it defaults to running the versions:set goal before initialize goal.
How can I define the initialize goal as a dependency of the versions:set goal?
IMO I should not need to define intermediate target ordering.
Note, I know I could use the versions plugin to do all of this but I need to manage gradle and maven versions from a parent gradle script, so I need the base newVersion to come from an external source so that I can use it from multiple build environments.
Re mvn ... initialize ... – You bound the read-project-properties goal of the properties-maven-plugin to the validate phase, so mvn validate should be sufficient. (Introduction to the Build Lifecycle, Default Lifecycle).
Invoking mvn ... versions:set without any phase executes the set goal of the versions plugin directly without passing through (any phase of) the default lifecycle. That means it doesn't „default to running the versions:set goal before initialize“, it doesn't pass the initialize phase (initialize is a phase not a goal) at all.
And there's also the following at Versions Maven Plugin, Basic Usage:
Maven 2.0, 2.1, 2.2 and 3.0 do not currently support re-reading modifications of the pom.xml within one invocation of Maven.
The following goals:
versions:set
...
modify the pom.xml file, you need to run these goals separately from any other goals or life-cycle phases.
I'm not aware of any way to define a phase as dependency of a goal but you can declare:
<build>
<defaultGoal>...</defaultGoal>
defaultGoal: the default goal or phase to execute if none is given. If a goal is given, it should be defined as it is in the command line (such as jar:jar). The same goes for if a phase is defined (such as install).
See POM Reference, The BaseBuild Element Set.

Run a single Maven plugin execution?

I thought I was an experienced Maven user, but I am having a mental block on how to do this!
I've been able to use the Maven sql plugin to drop, create, and install a schema in a database via plugin executions I've defined and bound to the pre-integration-test phase.
However, now I'd like to use that same sql plugin to insert some sample data whenever I want from the command line -- that is, not bound to any lifecycle goal. There are a few different sets of sample data, so I'd like to define a few different executions.
But is there a way to run one of these executions from the command line by using the execution ID perhaps?
As noted in How to execute maven plugin execution directly from command line?, this
functionality has been implemented as MNG-5768, and is available in Maven 3.3.1.
The change will:
extend direct plugin invocation syntax to allow optional #execution-id parameter, e.g., org.apache.maven.plugins:maven-remote-resources-plugin:1.0:process#executionId.
So, as long as you give your execution an id:
mvn sql:execute#specific-execution-id
uses the execution configured in your pom.
But is there a way to run one of these executions from the command line by using the execution ID perhaps?
No, not possible. What is possible though is to define "a" configuration to be used when the plugin is invoked from the command line using the "special" default-cli execution id:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>sql-maven-plugin</artifactId>
<version>1.4</version>
...
<executions>
<execution>
<id>default-cli</id>
<configuration>
...
</configuration>
</execution>
...
</executions>
</plugin>
And simply call mvn sql:execute.
See below for the details (from the Maven 2.2.0 Release Notes):
MNG-3401 - Starting in Maven 2.2.0,
goals invoked directly from the
command line can be configured in the
POM separately from other plugin
invocations using a special
executionId called default-cli.
Where previously, all configurations
for command-line goals had to go in
the plugin-level configuration, Maven
2.2.0 allows command-line-specific configurations to be separated into
their own <execution>. For more
information, see the Guide to Default
Execution IDs.

Resources