What's the best structure for a (multi-module) Maven project which should build "in the wild" without any Maven repository manager and can easily build within my organization where deployments should happen to my Maven repository manager?
Ideally, I would have two different paren POMs for each situation.
But unfortunately, I can't use a Maven property to pass the correct value for each situation, because the property expression in the parent POM reference doesn't get interpolated, if I try something like
<parent>
<groupId>org.example</groupId>
<artifactId>${root.pom}</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath/>
</parent>
...
<properties>
<root.pom>wild-parent</root.pom>
</properties>
Added a minimalistic project which shows a crude approach to solve this by patching the parent POM via sed.
This response on the maven-users mailing list pointed me in the direction to use Maven properties to pass in the in-house specifics.
I updated the example project.
Related
Per Maven documentation Maven will only look in local and remote repos for a parent pom after it fails to find it locally. The best solution I've found to dummy this out is by adding
<relativePath>.</relativePath>
which is obviously a kludge and produces warnings (as it well should). Maven seems to be like file-system coupling when dealing with parent modules and multi-module projects so this is the only way I see to have both of those co-exist without something that feels obviously wrong (e.g. inheriting from a filesystem child).
You reference the parent pom using the tag:
<parent>
<groupId>com.mycompany</groupId>
<artifactId>my-parentpom</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
You must install the parent pom into your local repo using the mvn install -N command from the directory that contains the parent POM.
I am currently updating a maven archetype for our project, and would like to reduce the quantity of information that users will have to give when using this archetype. The groupId will always be the same, for instance.
So, is it possible to define a default value for groupId in a Maven archetype ?
If you are working in a fixed organisation where this value will not change on a per project basis: Use a parent POM. Distribute it through your repository (you use some kind of central repository, even if it is only a network drive, do you?).
Inclusion in project
<artifactId>greattool</artifactId>
<packaging>war</packaging>
<parent>
<groupId>com.example</groupId>
<artifactId>master-parent-pom</artifactId>
<version>0.0.1</version>
</parent>
Parent POM
<groupId>com.example</groupId>
<artifactId>master-parent-pom</artifactId>
<version>0.0.1</version>
<packaging>pom</packaging>
<description>Parent POM for our projects, specific project type POMs derive from this.</description>
So no group id in the project POM, the one from the parent POM will be used. Of course you are replacing the group id with the inclusion of the parent POM but that is helpful as you can further customize Maven to your organisation's specific needs there.
If you use a build and test server you can even set the parent's version to -SNAPSHOT to automatically distribute changes in the parent POM to the project POMs.
I have all these version numbers throughout parent pom and children poms including the parent reference like so
<parent>
<groupId>com.cigna.ifp</groupId>
<artifactId>ifp-core</artifactId>
<version>${parent.version}</version>
</parent>
and dependency references to other child projects like so
<dependency>
<groupId>com.cigna.ifp</groupId>
<artifactId>ifp-shared</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
and finally the declaration of the version of the thing we are building
<modelVersion>4.0.0</modelVersion>
<groupId>com.company</groupId>
<artifactId>artifcat</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>ifp-shared</name>
<url>http://maven.apache.org</url>
EDIT based on some answers which solved half the question...
We want to have all the versions be ${project.version} since it is really just one project with one release number.
I can seem to do ${project.version} in the dependency but this does not work in the parent xml code above. Is there another way? (man, I should really just switch to gradle).
thanks,
Dean
<parent>
<groupId>com.cigna.ifp</groupId>
<artifactId>ifp-core</artifactId>
<version>1.2.3-SNAPSHOT</version> <!-- real version-->
</parent>
<artifactId>blah</artifactId>
<!-- No version here, will be inherited -->
<dependency>
<groupId>com.cigna.ifp</groupId>
<artifactId>ifp-shared</artifactId>
<version>${project.version}</version>
</dependency>
project.version is what you want. Not parent.version.
You need to use dependencyManagement tag to centerilize the versions in the parent pom for the dependencies.
See this question and answers
differences between dependencymanagement and dependencies in maven
For you your own modules, some of the properties are inherited from the parent pom. You will need to declare the parent version in each child but you don't need to declare a groupId/version in your child poms if you want them to be same as their parent's.
We switched to gradle which works fabulously now. Every automated build a new version is released as 1.2.x where x is the next build number. Downstream, projects depend on 1.2.+. This allows every release to be official so QA can test it, reject it or go, yup, build 1.2.568 is the release we will release to the world. Projects can depend on 1.2. but then they don't get bug fixes. This seems to work much better than all that snapshot nonsense as you give QA a snapshot and they approve and you have to change and do another build. We want every build to look official so they can release the one that happens to pass all QA tests.
E.g.:
<parent>
<groupId>mycompany.trade.com</groupId>
<artifactId>mycompany.trade.</artifactId>
<version>1.1.1.0-SNAPSHOT</version>
</parent>
Does it mean that Maven will search for parent pom?
If yes, where, in which order? May be in folder up 1 level? Or in local repository or in repo?
Yes, maven reads the parent POM from your local repository (or proxies like nexus) and creates an 'effective POM' by merging the information from parent and module POM.
See also Introduction to the POM
One reason to use a parent is that you have a central place to store information about versions
of artifacts, compiler-settings etc. that should be used in all modules.
The common dependencies,Properties,constants etc can be definded in central parent project pom.xml
The main important thing is the parent project cannot be distributed and it looks quite similar to a regular "pom.xml" except that it also has a packaging tag
<groupId>com.company.demo</groupId>
<artifactId>MavenInheritance</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
The child now able to inherit this using
<parent>
<groupId>com.company.demo</groupId>
<artifactId>MavenInheritance</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
As the name suggests, we can point out a parent pom.xml file for the current pom.xml file. Doing so, dependencies, properties, constants and many more defined at the parent pom.xml file also get merged with the current pom.xml (child pom.xml) file. Say you have a parent tag in your projects pom.xml that looks like below:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
</parent>
Then maven reads that parent POM from your local repository (or from repository managers like sonatype, jfrog, etc that you have configured) and creates a Resultant POM by combining the parent POM and your module’s POM.
To see the combined result use the following mvn command:
mvn help:effective-pom
This is the practice that is used in multi-modules projects where we need to inherit the dependencies from the parent projects.
I have a maven project - it is a plugin for jenkins. It's parent should be a:
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>1.414</version>
</parent>
But at the same time this plugin can be also used for hudson, without changing any line of code. But the parent project for it should be:
<parent>
<groupId>org.jvnet.hudson.plugins</groupId>
<artifactId>hudson-plugin-parent</artifactId>
<version>2.0.1</version>
</parent>
Can I specify 2 different profiles for that and use them to build plugin for jenkins or hudson accordingly? So that I call something like that:
mvn package -P jenkins
or
mvn package -P hudson
I have tried to specify properties in profiles, but those are not replaced by their values inside the <parent> tag. So is there any other possibility to build plugin for both, but with as much as possible common code and files?
Added: So, if I cannot do that, what should I do then? How to refactor? What the new structure should be?
As already mentioned, this is not possible.
Also, it is not possible to set a property for the parent's version as the interpolation for that happens a lot earlier than the handling of the profiles.
I would suggest that you create a masterbuild project as follows:
master
|-plugin-jenkins
|-plugin-hudson
|-plugin-assembly
The master should build all three as usual. However, in the assembly, you could add each of the two plugins as dependencies in separate profiles. And... each of these plugins can have the parent you like.
This is obviously somewhat a deviation from the Maven convention, but I believe it is a solution to your problem.
It's not possible because the tag "parent" is not available in the profiles section of the pom.
Currently we decided to stick with 1 repository and 2 separate pom.xml files, giving maven key which pom.xml use to build the project.
mvn package -f pom-jenkins.xml
mvn package -f pom-hudson.xml
No you cannot do that. you will have to refactor somehow to avoid the necessity.
As mentioned already not possible. I would suggest to make separate projects for jenkins plugin and hudson plugin. I assume that in not that far future that will not work anymore cause Hudons and Jenkins will diverge.
In general, you should be able to set the {group,artifact}Id and version of the parent POM via Java System Properties or Environment Variables, but it seems there is a Bug in Maven which will only be fixed in 4.x:
https://issues.apache.org/jira/browse/MNG-624
Another solution is to delegate the inclusion of the parent POM to your own parent POMs which you reference in the relativePath element, and change the content of the target e.g. via a symlink or cp command.
So in the main POM you would write:
<parent>
<groupId>org.mycompany.project</groupId>
<artifactId>foo-artifact</artifactId>
<version>1.0.0</version>
<relativePath>./my-parent.pom</relativePath>
</parent>
And in my-parent-jenkins you would just put:
<groupId>org.mycompany.project</groupId>
<artifactId>foo-artifact</artifactId>
<version>1.0.0</version>
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>1.414</version>
</parent>
The same project information with the block for hudson you put in my-parent-hudson.pom.
No you can either use
ln -s my-parent-jenkins.pom my-parent.pom
or
ln -s my-parent-hudson.pom my-parent.pom
to include the respective parent POM without the need to maintain two different main POM files for your project.
In case POM does not exist at the place referenced in relativePath, Maven will look up the POM in the remote repository[1], which is also an easy way to overwrite a parent POM locally.
[1] http://maven.apache.org/components/ref/3.3.9/maven-model/maven.html#class_parent