Share specific PMD rulesets across multi module maven project - maven

I'm trying to share the same pmd configuration across all my submodules. I'm looking for the best way to achieve that
I thought that I could place it in the parent project, like I did it for checkstyle plugin
Parent pom.xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>2.9.1</version>
<configuration>
<configLocation>/src/main/config/checkstyle.xml</configLocation>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>2.7.1</version>
<configuration>
<rulesets>
<ruleset>pmd.xml</ruleset>
</rulesets>
<linkXref>true</linkXref>
<sourceEncoding>${project.build.sourceEncoding}</sourceEncoding>
<targetJdk>${maven.compiler.target}</targetJdk>
</configuration>
</plugin>
</plugins>
</build>
Multi Module Structure
Here my structure
parent
|-- src
| `-- main
| `-- resources
| |-- pmd.xml
| `-- checkstyle.xml
|-- pom.xml
|-- model
| `-- pom.xml
`-- webapp
`-- pom.xml
Error
With this configuration, I only obtain the following error :
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-pmd-plugin:2.7.1:pmd (default-cli) on project model: An error has occurred in PMD Report report generation. Could not find resource 'pmd.xml'. -> [Help 1]
Solution 1
I tried this solution that works for me, because I only have one level on submodules :
But in a close future, I may have more levels, so I'm not convinced that's THE method
${basedir}/../src/main/resources/pmd.xml
Solution 2
Without writing all the solution, I can use an assembly to zip my config and use it in all my submodule as an dependency. This would work for any levels, but this is overkilling !
Here a link that would explain it: How to include resources from war to another maven project
So I'm looking for a Maven trick, but I don't what or how ! Every advice / clue is welcome.

Have a separate module that contains those generic config files like build-tools. Then you can add this module as a dependency to your plugin config and load it.
I have implemented an example of this with a checkstyle config file across a multiple modules in the ksoap2-android project.
https://github.com/mosabua/ksoap2-android/blob/master/pom.xml

I was reading the documentation for the ruleset tag and it says
The rule sets may reside in the classpath, filesystem or at a URL. For
rule sets that are bundled with the PMD tool, you do not need to
specificy the absolute path of the file. It will be resolved by the
plugin. But if the rule set is a custom rule set, you need to specify
its absolute path.
I solved the problem of sharing my PMD settings across my multi-maven build by specifying the URL to the ruleset file in my parent pom. (My repo was http accessible). Unfortunately this won't work though if you don't have your repo http accessible, but many people may.

Related

Spring Cloud Contract not deploying to Artifactory in Maven multi module projects

I have a multi module project in which each module deploys fine to Artifactory until I add spring-cloud-contract-maven-plugin to one of the modules (the service, as it is a producer API).
The project has this structure:
parent
- common (shared DTOs)
- client
- service
We want to remove the client and the common in the future and have Feign clients in the consumers for reducing the coupling, and have a basic project without inner modules, but for now we have to keep this structure.
I first noticed that the stubs were not pushed to Artifactory, so my initial workaround was to add this to the Jenkins pipeline
sh './mvnw clean deploy -U --projects=xxx-service'
It deploys the service and the stubs, but I noticed that none of the modules gets deployed when this command is executed:
sh './mvnw clean deploy -U'
This is the end of the output:
[INFO] Installing /xxx/xxx-service/target/xxx-service-1.7.0-SNAPSHOT.jar to /xxx/.m2/repository/xxx/xxx-service/1.7.0-SNAPSHOT/xxx-service-1.7.0-SNAPSHOT.jar
[INFO] Installing /xxx/xxx-service/pom.xml to /xxx/.m2/repository/xxx/xxx-service/1.7.0-SNAPSHOT/xxx-service-1.7.0-SNAPSHOT.pom
[INFO] Installing /xxx/xxx-service/target/xxx-service-1.7.0-SNAPSHOT-stubs.jar to /xxx/.m2/repository/xxx/xxx-service/1.7.0-SNAPSHOT/xxx-service-1.7.0-SNAPSHOT-stubs.jar
[INFO]
[INFO] --- maven-deploy-plugin:2.8.2:deploy (default-deploy) # xxx-service ---
[INFO] Deploying xxx:xxx-service:1.7.0-SNAPSHOT at end
I have tried to move all the Maven configuration to the parent POM file and keep the contracts and the base test classes in the service module. I have looked to this page that explains how to configure the plugin and I have seen that I can use contractsDirectory to specify the directory of the contract files, gmavenplus-plugin to specify the directory of the generated tests and packageWithBaseClasses to specify the package of the base classes. However I don't see any way to specify the directory of the base classes. I cannot move the base test classes to the parent because they use some classes of the service module for generating the mocks.
Is there any way of doing it or I have to create a separate project for the contracts?
Thanks in advance
Cause of the problem:
I had this in a parent project extended by my API:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>${maven-deploy-plugin.version}</version>
<configuration>
<deployAtEnd>true</deployAtEnd>
</configuration>
</plugin>
Why is this a problem:
maven-deploy-plugin seems to conflict with multi module projects with plugins that use extensions like spring-cloud-contract-maven-plugin. There is a known issue documented here, look to the answer of Jerome that is also here.
Solution 1:
Remove the deployAtEnd option from the previous block so it would be:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>${maven-deploy-plugin.version}</version>
</plugin>
Solution 2:
Configure the plugin in all the modules although they don't need it. For doing so:
Add an empty "contracts" folder under src/test/resources on all the modules
Add this to the pom file of the service module:
<build>
<plugins>
<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<version>${spring-cloud-contract.version}</version>
<extensions>true</extensions>
<configuration
<baseClassForTests>com.xxx.BaseContractTest</baseClassForTests>
</configuration>
</plugin>
</plugins>
</build>
Add this to the pom file of the other modules:
<build>
<plugins>
<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<version>${spring-cloud-contract.version}</version>
<extensions>true</extensions>
</plugin>
</plugins>
</build>

changing maven site plugin source folder

I need to change the maven site documentation source folder. I've check the plugin documentation and couldn't find this configuration.
Problem scenario:
I have a maven project with several child project, and one of this child is only a angular2 project.
On the angular project, the source folder has the pom.xml and several angular files, and one of the folder used by angular is 'src' (which is there the components, services, etc are stored).
I need to add maven site to this project, and it look the source files into 'src/site/*'. This works, but this 'site' folder is mixed with several ts files, and this looks messy, so I need to change the default folder for maven site plugin.
Is there any way to change it?
If you wish to change the source directory in which Maven looks for, although I would rather recommend to clean your directory, I think what's below should work:
<build>
....
<plugins>
....
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>3.4</version>
<configuration>
<siteDirectory>my/site/dir</siteDirectory>
</configuration>
</plugin>
....
</plugins>
....
</build>

sonar analysis on maven multimodule project with nonstandard directory structure

I'm trying to mavenize a project. The code base is beginning to bloat and it needs to be split into multiple modules. However, we already have a somewhat proprietary deployment process in place and the directory structure cannot be compromised in favor of the Maven way.
The simplified structure is as follows:
/workspace/basesrc/
|_ superpom.xml
|_ com/company/parentpkg/
|_ ModuleA/
|_ pom.xml
|_SubAModuleA/
|_ SubAModuleAClass.java
|_ pom.xml
|_SubAModuleB/
|_ SubAModuleBClass.java
|_ pom.xml
|_ ModuleB/
|_ ModuleBClass.java
|_ pom.xml
I was able to build the project using the following setup:
Approach A
(superpom.xml):
<build>
<sourceDirectory>.</sourceDirectory>
</build>
This is inherited by the submodules, in effect building only its current directory.
However, Sonar seems to have trouble resolving package names if this is the case as stated in this thread: mvn sonar:sonar throws exception while doing Java AST scan.
Approach B: Specify the root source directory and use maven compiler inclusions, as explained here: http://maven.apache.org/guides/mini/guide-using-one-source-directory.html
(superpom.xml)
<build>
<sourceDirectory>/workspace/basesrc/</sourceDirectory>
</build>
(SubAModuleA pom.xml)
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<includes><include>com/company/parentpkg/ModuleA/SubAModuleA/**/*.java</include></includes>
</configuration>
</plugin>
</plugins>
</build>
Again, this works for the case of maven build. But Sonar seems to include the whole /workspace/basesrc/ folder despite running mvn sonar:sonar from a submodule directory.
SO my question is,
If I use Approach A, is there a way to configure/override the root directory property in which Sonar Maven Plugin is searching for Java source files? Can it be different from the ${project.build.sourceDirectory} maven property?
Using Approach B, How can Sonar be configured to analyze only what is being built by maven-compiler-plugin?
For those who are interested, just to reiterate <sonar.includes> must be placed under <properties> instead of <configuration> under <plugin>. And sonar must be version 3.5 up.
well, I think following should help you to setup your project: http://maven.apache.org/guides/mini/guide-using-one-source-directory.html
See the section:
Producing Multiple Unique JARs from a Single Source Directory
Please understand that it's not the way things should be setup in maven, as you're breaking the convention, that makes maven so strong. On the other hand I understand that in some projects there is no option for changing the source structure to the way maven convention says it.

Sharing common resources between non-JAR maven projects

I have several Maven projects, say a,b,c, inheriting from a single parent (let's call it parent), and also being modules (of a different project than parent, let's call it super).
These projects all have a pom packaging. Each of these projects has specific configuration, but they also have a common part. To be more speficic, each project two JMeter test configuration files: one specialized for the given project, and another one that is common and identical for all projects.
The problem is - how should I configure the POMs so this common config file is shared among the projects?
A workaround would be to merge all of them into super, and use profiles. However, in this case, I would have to do a separate build for each configuration manually (whereas now I can just build super).
There are similar questions, like this one, but they deal with the jar plugin, which is not relevant for this case.
Structure, for reference:
POM Inheritance:
parent
|
-------------
| | |
a b c
File structure:
super
|
|-a
|
|-b
|
|-c
I have used the maven-remote-resources-plugin for a similar purpose. Create a separate resources project (com.company:resourceProj) of type jar. Put the JMeter resource files in /src/main/resources.
/src/main/resources/common.properties (your filenames obviously)
/src/main/resources/a.properties
etc.
Follow the directions in the example to create the bundle.
Now, add this config to your parent POM (in a testing profile if you want):
<properties>
<shared.resources.dir>${project.build.directory}/shared-resources</shared.resources.dir>
</properties>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-remote-resources-plugin</artifactId>
<executions>
<execution>
<id>load-resources</id>
<phase>initialize</phase>
<goals>
<goal>process</goal>
</goals>
<configuration>
<resourceBundles>
<resourceBundle>com.company:resourceProj:version</resourceBundle>
</resourceBundles>
<attached>false</attached>
<outputDirectory>${shared.resources.dir}</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
Now, tell Maven these are test resources. If your test resource elements are consistent across the modules, this can go in the parent too, if they are different it goes in the module POM. (In my experience with Maven 3 resources defined in a child project take precedence over the parent's; they aren't merged.)
<testResources>
<testResource>
<directory>${shared.resources.dir}</directory>
<includes>
<include>common.properties</include>
<include>${module.file}.properties</include>
</includes>
</testResource>
<!-- any other test resources here -->
</testResources>
In the child module, define the resources module property (this is module a):
<properties>
<module.file>a</module.file>
</properties>
Adapt this to meet your use case.
---- Edit ----
If the configuration is placed into a parent POM, the parent POM may fail to build depending on what configuration is provided by the child. When we are building the shared base/parent projects we don't want to require that all of the properties that should be provided by child projects (inheriters) are defined. So we activate this profile when building the shared projects to bypass anything that only applies to children.
To do this, add an empty file pom-packaging.marker to the parent project's basedir. Then add this profile to the parent POM. When the parent project is built, Maven will find the marker file, enable the profile, and disable all of the executions included in the profile. When a child project is built, the marker file doesn't exist, so the configuration in the main part of the POM will take effect.
I've used this technique with the Enforcer plugin as well - the parent defines the enforcer rules that should be applied to projects inheriting from the parent, but cannot satisfy the rules when it is built. If the plugin provides a "skip" property, you may enable that in this profile instead of using phase = none in plugin configuration.
<profile>
<id>pom-packaging</id>
<activation>
<file>
<exists>pom-packaging.marker</exists>
</file>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-remote-resources-plugin</artifactId>
<executions>
<execution>
<id>load-resources</id>
<phase>none</phase> <!-- disables this execution -->
</execution>
</executions>
</plugin>
.... other plugin executions here ....
</plugins>
</build>
</profile>
The idea with import scope dependencies is that you can put shared resources into a separate project, which is then imported by a number of other ones; I was thinking you could include your shared config file in this way.
You create a new project with packaging pom (maybe at the same level as the parent?), and then include it in the parent's dependencyManagement section with scope import. Each of your child projects can then receive it by inheritance. It might seem like overkill to make an entire project for just a single file, but I wouldn't have a problem with that.
I haven't actually tried this with a tree of pom-packaged projects, so you might have to play around a bit, but the approach I think is sound. There's a (very extensive) example here:
Importing Dependencies

Maven maven-glassfish-plugin in a multiproject setup

Short version:
I would like the maven-glassfish-plugin to only be executed in the root project in a hierarchical (inheritance based) maven multiproject setup.
Long version:
Following setup:
project-root
|
+-pom.xml
|
+ ear-module
| |
| +-pom.xml
|
+ jar-module
|
+-pom.xml
All submodules are included in the root project via <modules>...</modules> and all submodules inherit the root project pom.xml.
In my root project pom I include the maven-glassfish-plugin:
...
<plugin>
<groupId>org.glassfish.maven.plugin</groupId>
<artifactId>maven-glassfish-plugin</artifactId>
<version>2.1</version>
<inherited>false</inherited>
<configuration>
<glassfishDirectory>${glassfish.home}</glassfishDirectory>
<passwordFile>${glassfish.home}/masterpassword.txt</passwordFile>
<domain>
<name>${project.name}</name>
<adminPort>4848</adminPort>
<httpPort>8080</httpPort>
<httpsPort>8443</httpsPort>
<iiopPort>3700</iiopPort>
<jmsPort>7676</jmsPort>
</domain>
<components>
<component>
<name>poc.vermittler</name>
<artifact>${project.basedir}/ear-module/target/ear-project-1.0-SNAPSHOT.ear</artifact>
</component>
</configuration>
</plugin>
...
(Note: This is just an simplified version of my pom. It may not run :)
I want to only deploy the ear-module module to glassfish, this is why I added <inherited>false</inherited> section, and depict the modules to be deployed as <components>...</components> in the root pom.
Now the command:
mvn glassfish:deploy
Will deploy the ear to glassfish, all well so far... but then maven will decent recursively to all submodules, which will all fail with:
No plugin found for prefix 'glassfish' in the current project and in the plugin groups [org.apache.maven.plugins, org.codehaus.mojo] available from the repositories
I could tell maven to only run the root project with the -pl option but for my gusto, deploying shouldn't rely on such additional information.
Thanks a lot for your help!
It seems that there is no good solution to this problem:
either the plugin supports a "NOP"/silent discard functionality
or it will fail in all subprojects
Another method could be to create a new subproject (which is not included in the root project by <modules>...</modules> but inherits from the root project) and add dependencies to only the projects that have a deployment artifact.
The plugin can now be included in this subproject without it wanting to run any subproject.
Or for anybody who is lazy: mvn clean package glassfish:redeploy -pl . to selectively only run the root project without descending into child projects.

Resources