I have a Maven project shared with a team of people. While attempting to buildi it on Jenkins, I'm looking at the details of the project's parent pom. I'd like a confirmation of my interpretation of the following setting in parent pom:
<repository>
<id>m2-local</id>
<url>file:m2</url>
</repository>
To me, the above appears to refer to the parent's m2 folder of the project. But the id m2-local makes no sense to me. There are no other references of m2-local anywhere else in the pom. I also looked for m2-local in .m2/settings.xml, but nothing for it there either. Is it possible that m2-local has no significance at all here? Also, file:m2 is for Windows notation, but Jenkins is sitting on Linux. What should it look like on Linux?
<repository>
<id>m2-local</id>
<url>file:m2</url>
</repository>
This configuration is declaring a Maven repository, whose id is m2-local and that points to file:m2. The id is just an identifier and has no other meaning. What is more relevant is the URL.
It means that when Maven will try to look for dependencies, it will look for them at the URL file:m2, along with the URL of the other potential repositories. The URL file:m2 points to a folder on the local machine called m2 and located at the same place as the POM (this is because it is using a relative path). Such a notation is both valid in Windows and Linux.
Basically, it means that for your build to run on your Jenkins machine, you need to have a folder name m2 located at the root of the project (location of the POM) and Maven will look inside for artifacts.
I suggest you read Introduction to Repositories on the Maven documentation.
Related
Some background:
I have copied the master branch of an external github repository, not owned by me, into a personal repository
This repo contains a Java project and uses Maven for building and compilation
The group ID defined in all pom.xml files is org.mylibrary (let's assume)
When deploying to Artifactory, the deployment is done to myrepo/org/mylibrary/...
I'd like to deploy instead to:
myrepo/org/myorganization/mylibrary
but I would like to avoid editing all the pom.xml files, and replacing all lines containing:
<groupId>org.mylibrary</groupId>
with:
<groupId>org.myorganization.mylibrary</groupId>.
I'm configuring the deployment via the distributionManagement element:
<distributionManagement>
<repository>
<name>releases</name>
<id>deployment.credentials</id>
<url>https://artifactory.lab.myorg.org/artifactory/myrepo</url>
</repository>
</distributionManagement>
What's a clean way of solving this? Replacing the groupId definition in all pom.xml files does the trick, but, as said, that's something I want to avoid.
Thanks!
When deploying to any repository, Artifactory utilizes the layout that is configured for this repository. By default, for Maven repositories, Artifactory uses the "maven-default" layout.
I would recommend you to first add your requested layout and then configure your repository with the newly created layout.
I hope this information is found helpful.
Correct me if I'm wrong, but a Mirror is used to redirect all traffic to a specific repository URL and block everything else (including Maven central repo).
Now what if I have a Mirror to http://a.com:8081 and a repository to http://b.com:8081. Would the second URL ever get used? I assume the answer is a No. Can you have multiple Mirrors?
Correct me if I'm wrong, but a Mirror is used to redirect all traffic to a specific repository URL and block everything else (including Maven central repo).
This is not entirely correct. Artifacts are downloaded by Maven by searching them inside defined repositories. Those repositories are defined in project's POM or in the Maven settings. But, as specified in the Mirror documentation:
However, you may want to use an alternative mirror for a particular repository without changing the project files.
Let's take the example from the documentation and comment on it:
<mirrors>
<mirror>
<id>UK</id>
<name>UK Central</name>
<url>http://uk.maven.org/maven2</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
This defines a single mirror that will be used when Maven will want to fetch a dependency from the Maven Central Repository. Let's say you have 2 current repositories, which are Maven Central and a custom repo A. What happens is the following:
You are declaring a dependency to an artifact;
Maven will look for that dependency inside your defined repositories, so it will look for it inside the repository A and Maven Central;
Let's say it starts with A: it will hit the URL defined for that repository, like you would expect. Then let's say it wasn't found there;
It will then look inside Maven Central. However, Maven will notice that a mirror was configured for that repository. It will not hit Maven Central at repo1.maven.org. Instead, it will fetch it from uk.maven.org, which is the URL defined in the mirror configuration element.
As this example shows, a mirror only applies to certain repositories, which are defined with the <mirrorOf> configuration element. In the previous case, we had <mirrorOf>central</mirrorOf> which means "Mirror Maven Central". This element can have various values, and the documentation gives examples:
Examples:
* = everything
external:* = everything not on the localhost and not file based.
repo,repo1 = repo or repo1
*,!repo1 = everything except repo1:
Now what if I have a Mirror to http://a.com:8081 and a repository to http://b.com:8081. Would the second URL ever get used? I assume the answer is a No.
The above shows that the answer is not strictly no. The mirror to http://a.com:8081 will be used when Maven will try to fetch a dependency from one of the repository that it mirrors. If it indeed mirrors the repository to http://b.com:8081 then no requests will ever be made to http://b.com:8081 (they will be redirected to http://a.com:8081); but if it doesn't, Maven will continue to fetch dependencies from http://b.com:8081 like usual.
Can you have multiple Mirrors?
Yes, you can.
To answer your questions:
Correct me if I'm wrong, but a Mirror is used to redirect all traffic to a specific repository URL and block everything else (including Maven central repo).
Kind of right, but I would say all artifacts are redirected to the mirror.
The blocking doesn't happen because it's a mirror. The filtering or re-direction happens based on what is defined in the <mirrorOf> element.
The syntax <mirrofOf>*</mirrorOf> causes ALL repositories to be directed to that mirror. To use your words, the mirror blocks the other repository http://b.com:8081. (but I wouldn't use those words).
If, however, you defined the mirror pattern as:
<mirrofOf>*,!third-party-repo</mirrorOf>
then the mirror would handle all artifacts that were not found in the other repositories. So in this case (in your words), the mirror would not block access to the other repositories.
Now what if I have a Mirror to http://a.com:8081 and a repository to http://b.com:8081. Would the second URL ever get used? I assume the answer is a No.
This all depends on how you've defined your mirror and repositories as explained above, it is possible for them both to be used.
Can you have multiple Mirrors?
Yes. The maven docs explain how to do that here: https://maven.apache.org/guides/mini/guide-mirror-settings.html#advanced-mirror-specification
But I've never personally had the need to deal with multiple mirrors. Instead, I typically have one mirror and then one or more repos.
I'll explain that next.
Example using a mirror and two repos
In this example, I have:
One public mirror of Maven central (called acme-central) for my fictitious company Acme.
One repo for my companies locally developed artifacts (called acme-repo).
One repo for a 3rd party company third-party-repo that has some artifacts I needed (called third-party-repo).
The simplified syntax for all of this is shown below. I'm only showing the bits of the configuration that affect this example.
<settings>
<mirrors>
<mirror>
<mirrorOf>central,!acme-repo,!third-party-repo</mirrorOf>
<profiles>
<profile>
<id>default</id>
<repositories>
<repository>
<id>acme-repo</id>
<url>https://acme.com/repository/releases</url>
<repository>
<id>third-party-repo</id>
<url>https://third-party.com/repository/releases</url>
<activeProfiles>
<activeProfile>default</activeProfile>
So we have a mirror (of maven central), and two other repositories.
The mirror statement says to use the mirror instead of maven central, but not for the two repos acme-repo and third-party-repo.
The profile is required (just because that is the syntax of the settings.xml file). You can only define <repositories> within a profile.
The repositories have names, and the way artifacts are looked up is as follows (see Repository Order in Maven docs). What follows is simplified for this answer.
settings.xml file is used
pom.xml file is used
Before downloading from a repository, mirrors configuration is applied.
The maven docs show an example with two <mirror>s.
Running the command mvn help:effective-pom -Dverbose is a good way to see which repo/mirror was used to download an artifact because the syntax is:
Downloading from third-party-repo: https://third-party.com/...
Downloading from acme-repo: https://third-party.com/...
with maven 3 i have a parent project at 'C:/travail/parent'.
I have several child-projects who, for various reasons, can change locations.
To make a war, the relativePath tag must be set.
<parent>
<groupId>framework.parent</groupId>
<artifactId>parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>C:/Travail/parent/pom.xml</relativePath>
</parent>
Question: How can I put an absolute path for the parent? The following doesn't work.
<relativePath>/C:/Travail/parent/pom.xml</relativePath>
You cannot use an absolute path for your parent pom, the name itself of the configuration entry is quite self explanatory (relative path).
From the official Maven model documentation for this element:
The relative path of the parent pom.xml file within the check out. If not specified, it defaults to ../pom.xml. Maven looks for the parent POM first in this location on the filesystem, then the local repository, and lastly in the remote repo. relativePath allows you to select a different location, for example when your structure is flat, or deeper without an intermediate parent POM. However, the group ID, artifact ID and version are still required, and must match the file in the location given or it will revert to the repository for the POM. This feature is only for enhancing the development in a local checkout of that project. Set the value to an empty string in case you want to disable the feature and always resolve the parent POM from the repositories.
Default value is: ../pom.xml.
You can't even use a shortcut or symbolic link for the same, distributed together with each and every module and pointing at the absolute file location, it would not work (and you shouldn't use such a trick anyway, even if it was going to work).
You can't even use a property as value placeholder of the relativePath element. Something like:
<parent>
<groupId>framework.parent</groupId>
<artifactId>parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>${path.to.parent}</relativePath>
</parent>
And try to inject it at build time like:
mvn clean install -Dpath.to.parent=C:/somewhere/pom.xml
Would simply not work, as also documented by the following Maven tickets:
MNG-2569: Expressions not evaluated inside
MNG-624: automatic parent versioning
The only reasonable use case for this configuration entry is, as mentioned in the official documentation, for flat-structured multi-module projects, where modules and parent project are located at the same directory level.
Otherwise, and more suitable for your use case, you should provide the parent pom as part of the shared Maven repository (if any) or require a maven install (so that it will be available in the local maven cache) of the parent project upfront for any new version before any required maven action on the children/module projects.
It seems that Maven doesn't resolve variables until they are used in the child pom. This means that variables inherited from a parent like ${basedir} are incorrect when used by the child. For example, I have:
<repositories>
<repository>
<id>lib</id>
<url>file://${basedir}/mavenrepo</url>
</repository>
</repositories>
in my parent pom (because I'm using jars that haven't been pushed to any maven repo and I don't want to host my own).
I have a directory called 'mavenrepo' in my project root. However, when a child attempts to resolve this repo, the variable ${basedir} now points to the child project's directory and not the parent's base dir.
How can I force maven to resolve the ${basedir} to point to the directory that contains the parent pom?
The best i can suggest is to use a repository manager like Artifactory, Nexus or Archiva. Nexus has a very simple setup and makes life easier in particular if you have artiacts which not available via Central or other repositories.
In this relationship i can recommend to read Stephen Connolly blog about such kind of problem.
Apart from i would recommend to use Stephen Connolly's non-maven-jar-maven-plugin which should help in such situations.
I've got a Nexus Maven repository that I want to be the one and only repository used by my projects.
Per the Nexus documentation, To solve this problem I should change my local .m2/settings.xml.
Changing my settings.xml to solve this problem isn't a good practice, as it's not portable across different developer machines / CI servers.
What I want to do is change my global parent pom to say "use this and only this repository for all projects that use me as a parent." How can I do that? I see that I can add my repository as one of the repositories that are checked, but not the only repository. I tried cutting and pasting the 'mirror' section of the settings file to my pom, but 'mirror' is not allowed there.
Any ideas?
Thanks,
Roy
Tweak Nexus' instructions of modifying your $HOME/.m2/settings.xml. Have a networked settings file that refers to Nexus. This settings file should be used by all developers (and your CI server).
How do all developers refer to this one settings file?
There are a couple of ways of skinning that cat.
Option 1: Alias your Maven command.
On UNIX: alias mvn=mvn -s /networked/path/to/settings.xml
ON Windows: Open mvn.bat. Find mvn invocation and alter it similarly
Option 2: Home/settings linked to networked location
ON UNIX: cd $HOME; rm settings.xml;ln -s /networked/path/to/settings.xml settings.xml
ON Windows: I don't know the equivalent foo for symbolic linking
Assuming that you have a "standard" Maven install for all developers, you can change $M2_HOME/conf/settings.xml
Otherwise, you're out of luck with anything short of an intelligent network proxy.
Have you tried to configure the <repositories> element in your pom?
<project>
...
<repositories>
<repository>
<id>my-internal-site</id>
<url>http://myserver/repo</url>
</repository>
</repositories>
...
</project>
More information and details can be found at the Maven Internal Repositories page.