Maven does not reference the settings.xml for a repository when deploying - maven

I am trying to configure the deploy step in a Maven 3.0.4 POM using the <distributionManagement> tag. From XSD for POMs (line 1389), it suggests that merely providing the id should allow Maven too look up the corresponding values from the settings.xml file. I have the desired server listed (which is configured correctly since I can pull dependencies from it and see it mentioned when running in -X debug mode: [DEBUG] Repositories (dependencies): [archiva.snapshots (http://snap-mvnrepo.initech.com/archiva/repository/snapshots, releases+snapshots)]) in the settings.xml. However, when I just provide the <id> in my POM and try to deploy, I get an error that Maven is missing the URL for the repository, but when I explicitly provide the <url> the deploy works.
Does anyone know what I should do to get it working by id only? I don't want to hard code the URL.
DISCLAIMERS: Typos are likely the result of anonymization, but it is possible that they are "real" so feel free to point away at any.
About the <id> child tag of <repository> from the XSD for POMs (line 1389):
A unique identifier for a repository. This is used to match the repository to configuration in the settings.xml file, for example.
From my settings.xml:
<profile>
<id>archiva_dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<repositories>
<repository>
<id>archiva.snapshots</id>
<name>Initech Internal Snapshot Repository</name>
<url>http://snap-mvnrepo.initech.com/archiva/repository/snapshots</url>
</repository>
</repositories>
</profile>
From my (failing) pom.xml:
<distributionManagement>
<repository>
<id>archiva.snapshots</id>
<!--
<name>Initech Internal Snapshot Repository</name>
<url>http://snap-mvnrepo.initech.com/archiva/repository/snapshots</url>
-->
</repository>
</distributionManagement>
The error:
Caused by: java.lang.IllegalStateException: Failed to create release distribution repository for com.initech.ws:initechws:pom:1.0-SNAPSHOT
at org.apache.maven.project.MavenProject.getReleaseArtifactRepository(MavenProject.java:1853)
at org.apache.maven.project.MavenProject.getDistributionManagementArtifactRepository(MavenProject.java:1377)
at org.apache.maven.plugin.deploy.DeployMojo.getDeploymentRepository(DeployMojo.java:227)
at org.apache.maven.plugin.deploy.DeployMojo.execute(DeployMojo.java:118)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:101)
... 20 more
Caused by: org.apache.maven.artifact.InvalidRepositoryException: URL missing for repository archiva.snapshots
at org.apache.maven.repository.legacy.LegacyRepositorySystem.buildArtifactRepository(LegacyRepositorySystem.java:775)
at org.apache.maven.project.MavenProject.getReleaseArtifactRepository(MavenProject.java:1843)
... 24 more

The /project/distributionManagement/id value defines the /settings/servers/server/id to match against in order to identify the credentials to use when connecting to the url specified by /project/distributionManagement/url
Because the URL for deployment is very often different from the URL for read access, and the same credentials may apply to multiple URLs, there is no looking up of /project/repositories/repository or /project/pluginRepositories/pluginRepository.
The short answer is thus that you must specify /project/distributionManagement/url in order to be able to deploy, and if you need credentials in order to deploy to that URL you need to specify /project/distributionManagement/id and ensure that the matching credentials exist in your settings.xml
How could we update the documentation to make the above clearer and prevent future users from becoming confused in the manner you have been?
Update
The modello toolchain is generating the XSL with only some of the sentences, so
A unique identifier for a repository. This is used to match the repository to configuration in the settings.xml file, for example.
Is actually
A unique identifier for a repository. This is used to match the repository
to configuration in the settings.xml file, for example.
Furthermore, the identifier is used during POM inheritance and profile
injection to detect repositories that should be merged.
Source
Finally in order to fully make sense of the sentence, you need to be aware that the settings.xml file is just the source of settings when Maven is invoked from the command line. Maven Embedder may actually mean that the settings provided to Maven come from some other source entirely (think, e.g. from the configuration database of Eclipse or another IDE) which is the reason for some of the fun in MRELEASE-577.
A better way to read the first sentence might be
A unique identifier for a repository. This is used to match the repository to configuration, for example in the settings.xml file.
But if you can suggest something even better I will update the docs accordingly

Related

Why are settings.xml and pom.xml are not directing Maven to deploy to Artifactory?

I am trying to point Maven to a local Artifactory (OSS) repo (both on my Mac) so I can build code provided by a vendor. I have created an empty Maven local repo and virtual repo in Artifactory, and can use Generate Settings to create the snippets. My ID and encrypted password seem to be working OK in ~/.m2/settings.xml
I have updated the code's pom.xml file and that seems to be causing Maven to resolve from Artifactory.
No matter how I configure in ~/.m2/settings.xml or in the master settings.xml or with -Dmaven.repo.local, Maven wants to deploy to a disk path to the local repo.
If I specify a partial path, Maven says "Using local repository at " a path consisting of the code's home + the path I said.
If I specify a path starting with a / (root), Maven says "Using local repository at /whatever"
I want to specify "https://localhost/artifactory/reponame" so Maven will deploy there. Artifactory generates snippets that contain that kind of URL. But since a URL doesn't start with a /, Maven insists on prepending the code home location to the URL, which of course is nonsense.
There must be some combo of and or <distributionManagement> <repository> <id>central</id> <name> <url>https://localhost/artifactory/... that makes this work. What am I missing?
pom.xml snippet:
<distributionManagement>
<repository>
<id>central</id>
<name>LocalMac-releases</name>
<url>https://localhost/artifactory/TBX</url>
</repository>
<snapshotRepository>
<id>snapshots</id>
<name>LocalMac-snapshots</name>
<url>https://localhost/artifactory/TBX</url>
</snapshotRepository>
</distributionManagement>
Master settings.xml snippet: localRepository is commented out so it takes the default. When commented in whatever I enter does take effect... combined with ${user.home}.
<!-- localRepository
| The path to the local repository maven will use to store artifacts.
|
| Default: ${user.home}/.m2/repository
<localRepository>/path/to/local/repo</localRepository>
-->

How to publish all jar for an existing project in a nexus/sonartype?

I have a maven project, and I have already all my dependencies in my local host. I want to push all these dependencies into nexus/sonartype.
I don't want to push my jar one by one by uploading via nexus interface.
So I copied the content of my maven repository ($MAVEN_HOME/repository) into {nexus-data}/storage/public
Nexus have to recalculate index after restarting?
You might want to use Distribution Management -
<distributionManagement>
<repository>
<id>some-artifactory</id>
<name>Artifactory Name</name>
<url>http://your.artifactory.address/releases</url>
</repository>
<snapshotRepository>
<id>other-artifactory</id>
<name>Other Artifactory Name</name>
<url>http://your.artifactory.address/snapshots</url>
</snapshotRepository>
</distributionManagement>
Repository
Where as the repositories element specifies in the POM the location
and manner in which Maven may download remote artifacts for use by the
current project, distributionManagement specifies where (and how) this
project will get to a remote repository when it is deployed. The
repository elements will be used for snapshot distribution if the
snapshotRepository is not defined.
So I copied the content of my maven repository ($MAVEN_HOME/repository) into {nexus-data}/storage/public
Don't do that. In Nexus 3, Nexus doesn't use raw files so relying on this approach isn't going to work for you anyway.
You should be using distribution management as described by #nullpointer. If you can't for some reason, you could write a script to use Nexus' REST API to upload many artifacts. That's more useful when you aren't building using Maven. For example, maybe you have a whole pile of legacy jar files to upload.

Adding environment dependent parameters to the build

In my company's parent POM I specify corporate repositories, that we all use. The URLs contain server name and the path of course. Each time I change the POM I publish a new version.
Now imagine, that the server hosting our repos gets renamed. I can change all URLs in the parent POM (not a problem) and publish a new version with fixed URLs. But I can't change URLs in the existing versions of the parent POM.
This means, that I can't rebuild any artifact from the past.
Is there some standard way to get around this problem? Like:
Central property file
A configuration POM with a fixed 1.0.0-SNAPSHOT version, that get republished on any change?
You never put repositories except for distMngt in your POM. Again -- never. You have burned your POMs forever. This exists in Maven because repo managers did not exist back then. It is bad practice for years now and shall be removed.
Always use a Nexus instance with a repo group. This shall be added to your settings.xml which will mirror everything.
For those who don't believe, I am a long year Maven committer.
Another approach that we employ at work is to replace the URLs in the <distributionManagement> with parameters, like so:
<distributionManagement>
<repository>
<id>my-repo</id>
<name>My Release Repo</name>
<url>${url.deploy.releases}</url>
</repository>
<snapshotRepository>
<id>my-repo</id>
<name>My Release Repo</name>
<url>${url.deploy.snapshots}</url>
</snapshotRepository>
</distributionManagement>
This way, we use settings.xml to control where the artifacts should be deployed. This has the advantage that if you ever migrate a repository (which we did) you only need to update settings.xml for new builds/releases.
If you need to go back to an earlier release and republish (for whatever reason) you just checkout the release tag, set up settings.xml to point to the new repo and do a mvn clean deploy.
If you can't modify settings.xml you can always just copy it, change the copy and point out the new settings file with the -s flag.
This approach also works for <scm> tags.
If you use repositories in your parent pom and may change over time, the best strategy is in the URL or it use ALIAS (DNS, Apache redirect, Rewriting) and especially not the IP address directly , and you do not have to change the address of the repository every time.
Example:
<repositories>
<repository>
<id>myrepo</id>
<url>http://myrepo.me/content/repositories/public/</url>
</repository>
</repositories>
and:
http://myrepo.me/content/repositories/public/ => ip address 1.2.3.4/*/*/

Maven: how to find parent pom?

I am in the process of learning maven and setting up a build environment. One thing I can't figure out, how to set up a project such that it finds a company-wide parent pom. I would like this to work:
$ git clone some_project
$ cd some_project
$ mvn install some_project
The some_project/pom.xml should reference a company-wide pom which it could get from a company maven repository. But where do I specify the company repository?
Putting it in some_project/pom.xml would probably do but then the location is hardcoded in many projects, which could lead to quite some trouble down the road should the server location change.
Having it in settings.xml could work I guess but would break the above requirement.
Edit
Thanks for the answers. I am going with the settings.xml solution although it won't allow the above sequence of commands. Seems like there is no solution that does not require some sort of initial manual setup and of the proposed solutions settings.xml is the simplest to me. Therefore I can't decide which of the two answers to accept. Both are equally good.
Here's the part from settings.xml I came up with:
...
<profiles>
<profile>
<activation>
<property>
<name>!skip</name>
</property>
</activation>
<repositories>
<repository>
<id>internalrepo</id>
<name>Central Internal Maven Repository</name>
<url>http://server.company.example.com/mvnrepo</url>
</repository>
</repositories>
</profile>
</profiles>
...
I'd recommend putting it in settings.xml.
If your company runs its own maven repo, it makes sense to have this configured in settings.xml - especially as you may need to add things like access credentials, which of course should never appear in a (shared) project pom. The only downside is that each user will have to jump through one additional (one-time) hoop when first installing their maven client.
An alternative is to not actually get the root pom from the company maven repo initially, but instead install it directly into your local repo from git. If your root pom is itself a maven project (which is not uncommon) and is available in git, simply clone it and run mvn install.
Putting the company repository URL in settings.xml is considered a good practice. You can also have associated username/password needed for repository upload.
If you care about repository relocation, you must rely on a good DNS choice (repository.mycompany.com is generaly fine) and a good usage of web servers rewrite rules.

Adding maven nexus repo to my pom.xml

I have installed nexus on my local machine. I want my pom file to point to this repo. How can I add my custom repository to my pom.xml file?
From Maven - Settings Reference
The repositories for download and deployment are defined by the repositories and distributionManagement elements of the POM. However, certain settings such as username and password should not be distributed along with the pom.xml. This type of information should exist on the build server in the settings.xml.
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
...
<servers>
<server>
<id>server001</id>
<username>my_login</username>
<password>my_password</password>
<privateKey>${user.home}/.ssh/id_dsa</privateKey>
<passphrase>some_passphrase</passphrase>
<filePermissions>664</filePermissions>
<directoryPermissions>775</directoryPermissions>
<configuration></configuration>
</server>
</servers>
...
</settings>
id: This is the ID of the server (not of the user to login as) that matches the id element of the repository/mirror that Maven tries to connect to.
username, password: These elements appear as a pair denoting the login and password required to authenticate to this server.
privateKey, passphrase: Like the previous two elements, this pair specifies a path to a private key (default is ${user.home}/.ssh/id_dsa) and a passphrase, if required. The passphrase and password elements may be externalized in the future, but for now they must be set plain-text in the settings.xml file.
filePermissions, directoryPermissions: When a repository file or directory is created on deployment, these are the permissions to use. The legal values of each is a three digit number corrosponding to *nix file permissions, ie. 664, or 775.
Note: If you use a private key to login to the server, make sure you omit the element. Otherwise, the key will be ignored.
All you should need is the id, username and password
The id and URL should be defined in your pom.xml like this:
<repositories>
...
<repository>
<id>acme-nexus-releases</id>
<name>acme nexus</name>
<url>https://nexus.acme.net/content/repositories/releases</url>
</repository>
...
</repositories>
If you need a username and password to your server, you should encrypt it.
Maven Password Encryption
First of all I can highly recommend reading the Nexus book. It will explain the benefits of using a Maven repository manager.
There is a section on how to configure your Maven build to use Nexus:
http://www.sonatype.com/books/nexus-book/reference/config.html
This leads me to question why you altering your POM file? I suspect what you really want to do is setup Nexus as a remote repository mirror. This is done in your Maven settings file.
The following tells Maven use Nexus as your default repository (Instead of Maven Central)
<settings>
..
..
<mirrors>
<mirror>
<id>nexus</id>
<url>http://localhost:8081/nexus/content/groups/public</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
This is desired behaviour since your Nexus repository is configured to cache artifacts retrieved from Central (which is good for build performance).
Note:
The "public" repository group could include other repositories proxied by your Nexus instance (Not just Maven Central). You probabily want this behaviour, as it centralizes all repository management. It just makes your build less portable for people outside of your organization.
It seems the answers here do not support an enterprise use case where a Nexus server has multiple users and has project-based isolation (protection) based on user id ALONG with using an automated build (CI) system like Jenkins. You would not be able to create a settings.xml file to satisfy the different user ids needed for different projects. I am not sure how to solve this, except by opening Nexus up to anonymous access for reading repositories, unless the projects could store a project-specific generic user id in their pom.xml.
From the Apache Maven site
<project>
...
<repositories>
<repository>
<id>my-internal-site</id>
<url>http://myserver/repo</url>
</repository>
</repositories>
...
</project>
"The repositories for download and deployment are defined by the repositories and distributionManagement elements of the POM. However, certain settings such as username and password should not be distributed along with the pom.xml. This type of information should exist on the build server in the settings.xml." - Apache Maven site - settings reference
<servers>
<server>
<id>server001</id>
<username>my_login</username>
<password>my_password</password>
<privateKey>${user.home}/.ssh/id_dsa</privateKey>
<passphrase>some_passphrase</passphrase>
<filePermissions>664</filePermissions>
<directoryPermissions>775</directoryPermissions>
<configuration></configuration>
</server>
</servers>
If you don't want or you cannot modify the settings.xml file, you can create a new one at the root of your project, and call maven passing it as a parameter with the -s argument:
$ mvn COMMAND ... -s settings.xml
From maven setting reference, you can not put your username/password in a pom.xml
The repositories for download and deployment are defined by the repositories and distributionManagement elements of the POM. However, certain settings such as username and password should not be distributed along with the pom.xml. This type of information should exist on the build server in the settings.xml.
You can first add a repository in your pom and then add the username/password in the $MAVEN_HOME/conf/settings.xml:
<servers>
<server>
<id>my-internal-site</id>
<username>yourUsername</username>
<password>yourPassword</password>
</server>
</servers>

Resources