Order of maven multi module is not maintained for eclipse plugins - maven

We have a bunch of eclipse plugin projects, features and update sites. We have created a master pom where we define the modules:
<modules>
<module>bundles/b1</module>
<module>features/f1</module>
<module>p2/site1</module>
<module>bundles/b2</module>
</modules>
We wanted to preserve this order and as per Guide to working with Multiple Modules
As per the link above we assumed that the order will be preserved as per the order in which the module elements were listed.
Our requirement:
site1 produces a site_assembly.zip. We wanted to take this zip file and wrap into around into a bundle which is what "b2" bundle does.
Our observation:
Maven reactor order which is printed at the beginning of the multi-module build is proper, however the build for every module is forked.
Because of (1) the bundle b2 get built before the site1 project is build and is able to produce a site assembly zip.
We tried adding a dependency in "b2"'s pom.xml to site1 but the build failed as it tries to build b2 first which has dependency on site1 which has not been built till now.
We observed the same behavior when we had unit test as osgi fragment. In the order we clearly specified that the host comes before the test fragment but when the maven build is invoked then it always built the fragment before the host and it used to fail.
Plugins that are defined in master pom:
<plugin>
<!-- enable tycho build extension -->
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-maven-plugin</artifactId>
<version>${tycho-version}</version>
<extensions>true</extensions>
</plugin>
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>target-platform-configuration</artifactId>
<version>${tycho-version}</version>
<configuration>
<disableP2Mirrors>true</disableP2Mirrors>
<resolver>p2</resolver>
<target>
<artifact>
<groupId>com.x.y</groupId>
<artifactId>p2.build.target</artifactId>
<version>${project.version}</version>
<classifier>x</classifier>
</artifact>
</target>
</configuration>
</plugin>
We are not sure if maven-tycho-plugin interferes with the reactor order, so any help would be appreciated.

Tycho resolves the dependencies from the Eclipse descriptor files (MANIFEST.MF, feature.xml, etc.) and re-orders the modules so that required artifacts are built first.

Related

Exclude single module of multi-module project from aggregated report

I'm calling mvn site site:stage goal on multi-module project. One of the modules fails because in the chain of dependencies, which I can't influence, is reference to the http:// plugin repository.
This module is already excluded from site generation:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
The problem is, that the site plugin on the aggregator wants to include that project nevertheless and fails on maven-project-info-reports-plugin:3.4.1:dependency-convergence report. I don't need this module in site because it's no-java-source module (it calls plugin that verifies deployment to the application server).
How to configure reporting in the aggregator to exclude one module from generating aggregated report?

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>

Always run proguard-maven-plugin before install phase

What I am trying to do, is to obfuscate a certain packages in a multi module application, before it gets installed to my local repository, so that the final package will be an EAR file which contains obfuscated jars.
I tried to obfuscate the jars during EAR building process without success. Now i want to build the EAR with obfuscated jars instead ob obfuscating then during the build.
So I've got the following plugin configuration:
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<version>2.0.11</version>
<dependencies>
<dependency>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard-base</artifactId>
<version>${version.proguard}</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>proguard</goal>
</goals>
</execution>
</executions>
<configuration>
...
</configuration>
</plugin>
So there are two problems for me:
Progruard always runs after the install phase, so that the EAR build always gets the not obfuscated jars
I always have to add proguard:proguard to the maven command, which of course fails in a multi module project where some modules don't have to be obfuscated
So my questions:
How can I obfuscate the package before it gets installed?
How can I make plugins like this one run on default without adding <phase>:<goal> to the maven call?
Thnx.
It seems that for the proguard plugin to work, JAR files are needed. Perhaps you can achieve this by attaching the proguard plugin's proguard goal to the package phase (and not process-classes phase) of the default Maven build life cycle as proposed here by Alexey Shmalko. It's not clear to me if you are using the maven-shade-plugin, but if you are, then place the proguard plugin configuration your in pom.xml after that of maven-shade-plugin (this is because both these plugin attach to the same phase: package).
My expectation is that since package phase is achieved before install phase, it should give you the effect you are looking for.

How to use maven to publish multiple artifacts of an ivy project(with multiple modules) to a maven repository(nexus)

I'm working on a complex multi-module open source ivy project, which has ant's build.xml at the top level to kick off each ivy module's build. But the goal here is not to modify the original build scripts(both ivy.xml and build.xml), and using maven as an outer layer to kick off ant build, and then fetch the built results and publish them to nexus server.
The difficulty here is that, the built artifacts here are multiple jars, and we need to publish all these jars to nexus server with maven. Since one pom.xml only maps one maven artifafct, and in this case multiple artifacts are build not through maven but ivy. So I wonder if there's a feasible way to achieve my goal.
Currently, in the top level pom.xml, I'm using maven-antrun-plugin to invoke build.xml on top level, and using build-helper-maven-plugin to attache artifacts, but it doesont' work.
Currently I'm working on a similar task to yours. We have a huge, full of legacy system with whole build written in ant. That is how we handle this task:
No matter what, you will have to accept it, maven = jar per artifact (well, you can use attachments with qualifiers, but it's a real abuse and highly NOT recommended). It has it's philosophy after it: in the end of the day your system consists of (as you said yourself) modules, so each module has to have it's version, sources and (most important) the dependencies to other modules.
To reuse the existing ant code you can look on the antrun plugin. What we did, is "simply" separated all the common build code (i.e generators execution, attachments creation, assemblies and so on) to parent poms that are of type "pom". Then we execute the relevant targets simply by activating properties in children poms. Here is an example
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>EXECUTION_NAME</id>
<phase>generate-sources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target if="EXECUTION_TRIGGER_PROPERTY">
<taskdef resource="net/sf/antcontrib/antlib.xml"/>
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
And in the child pom we simply define
<properties>
<EXECUTION_TRIGGER_PROPERTY>true</EXECUTION_TRIGGER_PROPERTY>
</properties>
remember to look at maven lifecycle guide to choose the proper phase for your execution.
Don't forget that you can use maven plugins to make things easier. E.g instead of running <javac> task in ant, breaking to artifacts with jar type do all the compile for you. You can also find plugins that generate javadoc, jaxws and so on.
As you can see it's not that simple to make your system work with maven. It will require you to rethink how your build works. On the other hand the ability to see and understand your dependencies, the ease of working in modern IDE's, binary repositories and so on are worth it in most of the cases.

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

Resources