How to force Maven to use a specific repository (and only that)? - maven

I am setting up a local Nexus repository and am trying to convince my local Maven setup to access that repo as the one and only. That Nexus repo has a group maven-central defined that (quoting from the Nexus manual:) "...accesses the Central Repository, formerly known as Maven Central." and is also supposed to cache the downloaded data.
I thus entered my local Nexus repo into my [home]\.m2\settings.xml like this:
...
<profile>
<id>alwaysActiveProfile</id>
<repositories>
<repository>
<id>RepoSynoProxy</id>
<name>Nexus Repo on Synology NAS</name>
<url>http://192.168.1.15:8081/repository/maven-central/</url>
</repository>
</repositories>
</profile>
</profiles>
...
<activeProfiles>
<activeProfile>alwaysActiveProfile</activeProfile>
</activeProfiles>
...
But for some strange reason, when I run Maven it starts downloading everything from https://repo.maven.apache.org/maven2/ instead of from the local URL, as I would have expected:
...
[INFO] Downloading from : http://192.168.1.15:8081/repository/maven-central/junit/junit/3.8.1/junit-3.8.1.pom
[INFO] Downloading from : https://repo.maven.apache.org/maven2/junit/junit/3.8.1/junit-3.8.1.pom
[INFO] Downloaded from : https://repo.maven.apache.org/maven2/junit/junit/3.8.1/junit-3.8.1.pom (998 B at 7.3 kB/s)
[INFO] Downloading from : http://192.168.1.15:8081/repository/maven-central/junit/junit/3.8.1/junit-3.8.1.jar
[INFO] Downloading from : https://repo.maven.apache.org/maven2/junit/junit/3.8.1/junit-3.8.1.jar
[INFO] Downloaded from : https://repo.maven.apache.org/maven2/junit/junit/3.8.1/junit-3.8.1.jar (121 kB at 1.4 MB/s)
...
My questions thus:
First: any idea anyone, why the requests to http://192.168.1.15:8081/repository/maven-central/... obviously don't work? I am using a freshly downloaded and installed Nexus v3.18.0 here. The Maven-central proxy is already predefined and I have nothing special configured. Apparently that doesn't work "out-of-the-box".
Second: where does Maven have the URL https://repo.maven.apache.org/maven2/... from that it is using as alternative? Is that hardcoded into Maven as fall-back if a repo doesn't work? Can one suppress that so that it ONLY accesses the repo defined in settings.xml?

You need to configure a mirror in the settings.xml that will override the repository definitions in the superpom and in other pom files: https://help.sonatype.com/display/NXRM3/Maven+Repositories#MavenRepositories-ConfiguringApacheMaven

Related

Maven Build Failure -- DependencyResolutionException

I'm installing a package that has Maven dependency and get a DependencyResolutionException when I try to clean it.
After cloning it, I navigate to the directory and run the following to install it with no error:
mvn install:install-file -Dfile=./lib/massbank.jar -DgroupId=massbank -DartifactId=massbank -Dversion=1.0 -Dpackaging=jar
mvn install:install-file -Dfile=./lib/metfusion.jar -DgroupId=de.ipbhalle.msbi -DartifactId=metfusion -Dversion=1.0 -Dpackaging=jar
Then:
mvn clean package
with the following console output:
[INFO] Scanning for projects...
[INFO]
[INFO] --------------------< MassBank2NIST:MassBank2NIST >---------------------
[INFO] Building MassBank2NIST 0.0.2-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.450 s
[INFO] Finished at: 2021-04-07T01:08:28-04:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal on project MassBank2NIST: Could not resolve dependencies for project MassBank2NIST:MassBank2NIST:jar:0.0.2-SNAPSHOT: Failed to collect dependencies at edu.ucdavis.fiehnlab.splash:core:jar:1.8: Failed to read artifact descriptor for edu.ucdavis.fiehnlab.splash:core:jar:1.8: Could not transfer artifact edu.ucdavis.fiehnlab.splash:core:pom:1.8 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [EBI (http://www.ebi.ac.uk/intact/maven/nexus/content/repositories/ebi-repo/, default, releases+snapshots), releases (http://gose.fiehnlab.ucdavis.edu:55000/content/groups/public, default, releases+snapshots)] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/DependencyResolutionException
I can post the output of the debug logging switch if necessary, but it's quite long. I can also post the pom.xml, however it refers to the repositories as required from what I can tell.
I've searched for similar posts, but none seem to contain the same series of errors or similar. Can someone help me decipher these errors?
Thanks!
You don't have to downgrade Maven. What happens here is that since 3.8.1, Maven comes with a default configuration to block all HTTP (insecure) repositories. The best way would be to upgrade your repositories and make them secure (HTTPS).
However, you can tell Maven to allow downloading from your insecure repository by adding this mirror to your ~/.m2/settings.xml:
<mirror>
<id>insecure-repo</id>
<mirrorOf>external:http:*</mirrorOf>
<url>http://www.ebi.ac.uk/intact/maven/nexus/content/repositories/ebi-repo/</url>
<blocked>false</blocked>
</mirror>
Setting blocked to false will fix your issue. Note that above snippet assumes that the repository at www.ebi.ac.uk mirrors all insecure HTTP repositories (which is what external:http:* means).
You can also unblock individual repositories. For example, the JasperSoft repository is insecure, I unblock it with:
<mirror>
<id>jaspersoft-third-party-mirror</id>
<mirrorOf>jaspersoft-third-party</mirrorOf>
<url>http://jaspersoft.jfrog.io/jaspersoft/third-party-ce-artifacts/</url>
<blocked>false</blocked>
</mirror>
Open file ${MAVEN_HOME}/conf/settings.xml
And Comment these lines.
<mirror>
<id>maven-default-http-blocker</id>
<mirrorOf>external:http:*</mirrorOf>
<name>Pseudo repository to mirror external repositories initially using HTTP.</name>
<url>http://0.0.0.0/</url>
<blocked>false</blocked>
</mirror>
If you do not have access to ~/.m2/settings.xml because your build is handled by cloud CI/CD or you want to share this solution with your team members. The best way is to create your own maven setting file in the project.
Create .mvn folder in your project.
Create custom-settings.xml file inside .mvn folder with such content (in this example we unblock http connection for releases.java.net mirror):
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 http://maven.apache.org/xsd/settings-1.2.0.xsd">
<mirrors>
<mirror>
<id>releases-java-net-http-unblocker</id>
<mirrorOf>releases.java.net</mirrorOf>
<name>releases.java.net</name>
<url>http://maven.java.net/content/repositories/releases/</url>
<blocked>false</blocked>
</mirror>
</mirrors>
</settings>
Create maven.config file inside .mvn folder with such content:
--settings ../.mvn/custom-settings.xml
Or you can just run mvn clean install --settings .mvn/custom-settings.xml.
The error "Blocked mirror for repositories" is referred to explicitly in Maven's release note for version 3.8.1:
How to fix when I get a HTTP repository blocked?
If the repository is defined in your pom.xml, please fix it in your source code.
If the repository is defined in one of your dependencies POM, you’ll get a message like:
[ERROR] Failed to execute goal on project test: Could not resolve dependencies for project xxx: Failed to collect dependencies at my.test:dependency:version -> my.test.transitive:transitive:version: Failed to read artifact descriptor for my.test.transitive:transitive:jar:version: Could not transfer artifact my.test.transitive:transitive:pom:version from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [blocked-repository-id (http://blocked.repository.org, default, releases+snapshots)]
They go on to offer some ways to avoid the problem:
Options to fix are:
upgrade the dependency version to a newer version that replaced the obsolete HTTP repository URL with a HTTPS one,
keep the dependency version but define a mirror in your settings.
Plus, I suppose, the simpler, shorter-term option would be to roll back your version of Maven to anything prior to 3.8.1.
Use apache-maven-3.6.3, which uses http only
https://downloads.apache.org/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.zip
use apache-maven-3.8.1, adding the following in ~/.m2/settings.xml could solve such problem:
<mirrors>
<mirror>
<id>internal-repository</id>
<name>Maven Repository Manager running on https://repo1.maven.org/maven2</name>
<url>https://repo1.maven.org/maven2</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
Refer to this link https://maven.apache.org/guides/mini/guide-mirror-settings.html to see why the error occurred.
I had a similar problem but with Vaadin.
There is the simplest solution possible, and it is to replace all http:// with https://
This is an example :
<repository>
<id>vaadin-addons</id>
<url>https://maven.vaadin.com/vaadin-addons</url>
</repository>
This is due to latest maven blocks insecure HTTP connections. One possibility is adding a mirror to maven settings.xml. Best way is updating the pom file to refer to secure HTTPS repository if it is available. For example I faced the same issue with following config in pom.xml.
<repositories>
<repository>
<releases>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
<checksumPolicy>ignore</checksumPolicy>
</releases>
<id>wso2-nexus</id>
<url>http://maven.wso2.org/nexus/content/groups/wso2-public/</url>
</repository>
</repositories>
I was able to resolve the issue by updating URL as bellow. Here I referred to HTTPS repo which was available in my case.
<url>https://maven.wso2.org/nexus/content/groups/wso2-public/</url>
For me, I had to downgrade to the older version 3.6.3 from the site and the crazy problem is gone, hope maven community can fix this problem without us doing anything to our settings.xml.
apache-maven-3.6.3-bin will resolve the maven-default-http-blocker (http //0.0.0.0/) blocked Issue (fixed for me) it works for me
New mvn versions do not support http (insecure repos)
ultimately had to downgrade to mvn 3.5
brew uninstall maven
Instructions to install mvn 3.5 can be found at
https://formulae.brew.sh/formula/maven#3.5

Maven build on AWS wrongly using SNAPSHOT private repo

We have a private maven repo (artifactory) and we have a release jar (cryptolib-0.9.7.jar) in the libs-release folder.
Building locally or on Jenkins (hosted on Azure), all works fine. Building on codebuild on AWS, maven tries (and fails) to download from libs-snapshot instead.
Jenkins & local output (v3.3.9)...
Downloading: http://[our-repo]/artifactory/libs-release/org/openpseudonymiser/cryptolib/0.9.7/cryptolib-0.9.7.pom
Downloaded: http://[our-repo]/artifactory/libs-release/org/openpseudonymiser/cryptolib/0.9.7/cryptolib-0.9.7.pom (457 B at 3.7 KB/sec)
Downloading: http://[our-repo]/artifactory/libs-release/org/openpseudonymiser/cryptolib/0.9.7/cryptolib-0.9.7.jar
Downloaded: http://[our-repo]/artifactory/libs-release/org/openpseudonymiser/cryptolib/0.9.7/cryptolib-0.9.7.jar (13 KB at 234.8 KB/sec)
AWS/CodeBuild output (v.3.3.3)...
Downloading: http://[our-repo]/artifactory/libs-snapshot/org/openpseudonymiser/cryptolib/0.9.7/cryptolib-0.9.7.jar
Both are executing mvn -B install. I've tried all sorts of online suggestions and the the pom repository section currently looks like this (which now seems to ONLY attempt download from central)...
<repositories>
<repository>
<releases><enabled>false</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
<id>snapshots</id>
<name>libs-snapshot</name>
<url>http://[our-repo]/artifactory/libs-snapshot</url>
</repository>
<repository>
<releases><enabled>true</enabled></releases>
<snapshots><enabled>false</enabled></snapshots>
<id>central</id>
<name>libs-release</name>
<url>http://[our-repo]/artifactory/libs-release</url>
</repository>
</repositories>
What am I missing (apart from hair!!!)??
Doh! "When you use Maven with an AWS CodeBuild provided Java build environment, Maven pulls build and plugin dependencies from the secure central Maven repository at repo1.maven.org/maven2. This happens even if your build project's pom.xml file explicitly declares other locations to use instead." http://docs.aws.amazon.com/codebuild/latest/userguide/troubleshooting.html#troubleshooting-maven-repos
My solution was to delete the default settings.xml in the buildspec install phase.
phases:
install:
commands:
- rm /root/.m2/settings.xml

How do I force Maven to use my local repository rather than going out to remote repos to retrieve artifacts?

I’m using Maven 3.3.3 with Java 8 on Mac Yosemite. I have a multi-module project.
<modules>
<module>first-module</module>
<module>my-module</module>
…
</modules>
When I build my one of my child modules, for example, “my-module” from above, using “mvn clean install”, the build attempts to download the child module artifacts from a remote repository I have defined in my ~/.m2/settings.xml file. Output is below
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building my-module 87.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
Downloading: https://my.remoterepository.com/nexus/content/repositories/snapshots/org/mainco/subco/first-module/87.0.0-SNAPSHOT/maven-metadata.xml
Downloading: http://download.java.net/maven/2/org/mainco/subco/first-module/87.0.0-SNAPSHOT/maven-metadata.xml
Downloaded: https://my.remoterepository.com/nexus/content/repositories/snapshots/org/mainco/subco/first-module/87.0.0-SNAPSHOT/maven-metadata.xml (788 B at 0.9 KB/sec)
Downloading: https://my.remoterepository.com/nexus/content/repositories/snapshots/org/mainco/subco/first-module/87.0.0-SNAPSHOT/first-module-87.0.0-20151104.200545-4.pom
How do I force Maven to check my local ~/.m2/repository first before trying to download from the remote repositories? Below is where I have my remote repositories defined in my ~/.m2/settings.xml file …
<profile>
<id>releases</id>
<activation>
<property>
<name>!releases.off</name>
</property>
</activation>
<repositories>
<repository>
<id>releases</id>
<url>https://my.remoterepository.com/nexus/content/repositories/releases/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</profile>
<profile>
<id>snapshots</id>
<activation>
<property>
<name>!snapshots.off</name>
</property>
</activation>
<repositories>
<repository>
<id>snapshots</id>
<url>https://my.remoterepository.com/nexus/content/repositories/snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</profile>
Edit: In response to the answer saying that the download occurs when the artifact is not there, below is the terminal output in which I prove the file was there in my repo but Maven is trying to download it anyway ...
Daves-MacBook-Pro-2:my-module davea$ ls -al ~/.m2/repository/org/mainco/subco/first-module/87.0.0-SNAPSHOT/first-module-87.0.0-SNAPSHOT.jar
-rw-r--r-- 1 davea staff 10171 Nov 5 10:22 /Users/davea/.m2/repository/org/mainco/subco/first-module/87.0.0-SNAPSHOT/first-module-87.0.0-SNAPSHOT.jar
Daves-MacBook-Pro-2:my-module davea$ mvn clean install
[INFO] Scanning for projects...
[WARNING]
[WARNING] Some problems were encountered while building the effective model for org.mainco.subco:my-module:jar:87.0.0-SNAPSHOT
[WARNING] 'build.plugins.plugin.(groupId:artifactId)' must be unique but found duplicate declaration of plugin org.apache.maven.plugins:maven-antrun-plugin # org.mainco.subco:my-module:[unknown-version], /Users/davea/Documents/sb_workspace/my-module/pom.xml, line 678, column 12
[WARNING]
[WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
[WARNING]
[WARNING] For this reason, future Maven versions might no longer support building such malformed projects.
[WARNING]
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building my-module 87.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
Downloading: https://my.remoterepository.com/nexus/content/repositories/snapshots/org/mainco/subco/first-module/87.0.0-SNAPSHOT/maven-metadata.xml
Downloading: http://download.java.net/maven/2/org/mainco/subco/first-module/87.0.0-SNAPSHOT/maven-metadata.xml
Downloaded: https://my.remoterepository.com/nexus/content/repositories/snapshots/org/mainco/subco/first-module/87.0.0-SNAPSHOT/maven-metadata.xml (788 B at 0.8 KB/sec)
Downloading: https://my.remoterepository.com/nexus/content/repositories/snapshots/org/mainco/subco/first-module/87.0.0-SNAPSHOT/first-module-87.0.0-20151106.043202-8.pom
Downloaded: https://my.remoterepository.com/nexus/content/repositories/snapshots/org/mainco/subco/first-module/87.0.0-SNAPSHOT/first- module-87.0.0-20151106.043202-8.pom (3 KB at 21.9 KB/sec)
Downloading: http://download.java.net/maven/2/org/mainco/subco/subco/87.0.0-SNAPSHOT/maven-metadata.xml
Downloading: https://my.remoterepository.com/nexus/content/repositories/snapshots/org/mainco/subco/subco/87.0.0-SNAPSHOT/maven-metadata.xml
The dependency has a snapshot version. For snapshots, Maven will check the local repository and if the artifact found in the local repository is too old, it will attempt to find an updated one in the remote repositories. That is probably what you are seeing.
Note that this behavior is controlled by the updatePolicy directive in the repository configuration (which is daily by default for snapshot repositories).
Use mvn --help and you can see the options list.
There is an option like -nsu,--no-snapshot-updates Suppress SNAPSHOT updates
So use command mvn install -nsu can force compile with local repository.
To truly force maven to only use your local repo, you can run with mvn <goals> -o. The -o tells maven to let you work "offline", and it will stay off the network.
Follow below steps:
Ensure to delete all the contents of the jar folder located in your local except the jar that you want to keep.
For example files like .repositories, .pom, .sha1, .lastUpdated etc.
Execute mvn clean install -o command
This will help to use local repository jar files rather than connecting to any repository.
Maven always checks your local repository first, however,your dependency needs to be installed in your repo for maven to find it.
Run mvn install in your dependency module first, and then build your dependent module.
In my case I had a multi module project just like you. I had to change a group Id of one of the external libraries my project was depending on as shown below.
From:
<dependencyManagement>
<dependency>
<groupId>org.thirdparty</groupId>
<artifactId>calculation-api</artifactId>
<version>2.0</version>
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependencyManagement>
To:
<dependencyManagement>
<dependency>
<groupId>org.thirdparty.module</groupId>
<artifactId>calculation-api</artifactId>
<version>2.0</version>
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependencyManagement>
Pay attention to the <groupId> section. It turned out that I was forgetting to modifiy the corresponding section of the submodules that define this dependency in their pom files.
It drove me very crazy because the module was available locally.
Even when considering all answers above you might still run into issues that will terminate your maven offline build with an error. Especially, you may experience a warning as follwos:
[WARNING] The POM for org.apache.maven.plugins:maven-resources-plugin:jar:2.6 is missing, no dependency information available
The warning will be immediately followed by further errors and maven will terminate.
For us the safest way to build offline with a maven offline cache created following the hints above is to use following maven offline parameters:
mvn -o -llr -Dmaven.repo.local=<path_to_your_offline_cache> ...
Especially, option -llr prevents you from having to tune your local cache as proposed in answer #4.
Also take care that parameter <localRepositoryin> in your settings.xml points to the correct folder of your local Maven repository.
The -o option didn't work for me because the artifact is still in development and not yet uploaded and maven (3.5.x) still tries to download it from the remote repository because it's the first time, according to the error I get.
However this fixed it for me: https://maven.apache.org/general.html#importing-jars
After this manual install there's no need to use the offline option either.
UPDATE
I've just rebuilt the dependency and I had to re-import it: the regular mvn clean install was not sufficient for me
I had the exact same problem. Running mvn clean install instead of mvn clean compile resolved it.
The difference only occurs when using multi-maven-project since the project dependencies are uploaded to the local repository by using install.
use <classpathentry kind="var" path="M2_REPO/your jar location
without creating any environment veriable
just to give my 2 cents. For me, it was only necessary to find the jar inside the ~/.m2/repository directory and use its version. So, after using
cd local-dependency/
mvn install
the local-dependency jar will be in the .m2/repository/com/your-organization/local-dependency/
~$ tree ~/.m2/repository/com/your-organization/local-dependency/
/home/felipe/.m2/repository/com/your-organization/local-dependency/
├── 0.1-SNAPSHOT
│   ├── maven-metadata-local.xml
│   ├── _remote.repositories
│   ├── local-dependency-0.1-SNAPSHOT.jar
│   ├── local-dependency-0.1-SNAPSHOT.pom
│   └── resolver-status.properties
└── maven-metadata-local.xml
then use it as a local dependency
<dependency>
<groupId>com.your-organization</groupId>
<artifactId>local-dependency</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>

Maven local repository in settings.xml vs pom.xml

I am new to Maven. I would like to use the following setup:
1) a remote repository to download public artifact
2) a shared local repository for downloaded artifacts which works nicely by adding the following to settings.xml:
<localRepository>C:/m2repo</localRepository>
3) Now I would also like to have a repository for artifacts referenced
from a single project, like an old-fashioned "lib" folder.
So I have added the following to the project's pom.xml:
<repository>
<id>repo</id>
<name>repo</name>
<releases>
<enabled>true</enabled>
<checksumPolicy>ignore</checksumPolicy>
</releases>
<url>${project.baseUri}repo</url>
</repository>
I have deployed some jars to the "repo" folder, but when I add them as dependencies in pom.xml, they are not resolved. Maven only looks to the shared repository and the remote repository. When I copy the contents of "repo" to the shared "m2repo", it works. Am I missing something or is this setup not possible at all?
Though possible, personally I do not think that it is a good practice to do that. Depending on your usage this post will be helpful: http://blog.sonatype.com/people/2009/02/why-putting-repositories-in-your-poms-is-a-bad-idea. You also want a reproducible and portable project, this question discusses this related topic. Please don't check in those jars into your VCS just for portability sake!
I will try to help if you still insist. To make your model to work, your "repo folder" must follow the structure defined here.
Even though your "repo folder" is a local file structure, Maven will still treat it as if it is a remote repository, just like maven central. This means, whenever you are building your project, Maven will try to download the jars from your "repo folder" to your .m2 repository too:
Downloading: file:/j/my-project/my-local-repo/com/google/guava/guava/14.0.1/guava-14.0.1.pom
Downloaded: file:/j/my-project/my-local-repo/com/google/guava/guava/14.0.1/guava-14.0.1.pom (6 KB at 276.3 KB/sec)
Downloading: http://repo.maven.apache.org/maven2/com/google/google/1/google-1.pom
Downloaded: http://repo.maven.apache.org/maven2/com/google/google/1/google-1.pom (2 KB at 10.4 KB/sec)
You can see that the guava jar will be downloaded from the "repo folder" to my .m2 repository since it is available from my "repo folder".
The cause of my problem was the mirroring of repositories in my settings.xml, I have mirroring set to all repositories:
<mirror>
<mirrorOf>*</mirrorOf>
</mirror>
which I changed to only external repositories:
<mirror>
<mirrorOf>external:*</mirrorOf>
</mirror>
Now my artifacts are found in the "project" repository. However, Maven behaves differently than I expected, as ceilfors writes, the filesystem repository is treated the same as remote repositories - artifacts are copied from there to the local repository, which leads to duplication of jars between the local repository and other filesystem repositories. So I see the setting is not ideal. However, in my case, I still find it the quickiest way to mavenize the project.

Hosting a Maven repository on github

I have a fork of a small open sourced library that I'm working on github. I'd like to make it available to other developers via maven, but I don't want to run my own Nexus server, and because it's a fork I can't easily deploy it to oss.sonatype.org.
What I'd like to do is to deploy it to github so that others can access it using maven. What's the best way to do this?
The best solution I've been able to find consists of these steps:
Create a branch called mvn-repo to host your maven artifacts.
Use the github site-maven-plugin to push your artifacts to github.
Configure maven to use your remote mvn-repo as a maven repository.
There are several benefits to using this approach:
Maven artifacts are kept separate from your source in a separate branch called mvn-repo, much like github pages are kept in a separate branch called gh-pages (if you use github pages)
Unlike some other proposed solutions, it doesn't conflict with your gh-pages if you're using them.
Ties in naturally with the deploy target so there are no new maven commands to learn. Just use mvn deploy as you normally would
The typical way you deploy artifacts to a remote maven repo is to use mvn deploy, so let's patch into that mechanism for this solution.
First, tell maven to deploy artifacts to a temporary staging location inside your target directory. Add this to your pom.xml:
<distributionManagement>
<repository>
<id>internal.repo</id>
<name>Temporary Staging Repository</name>
<url>file://${project.build.directory}/mvn-repo</url>
</repository>
</distributionManagement>
<plugins>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.1</version>
<configuration>
<altDeploymentRepository>internal.repo::default::file://${project.build.directory}/mvn-repo</altDeploymentRepository>
</configuration>
</plugin>
</plugins>
Now try running mvn clean deploy. You'll see that it deployed your maven repository to target/mvn-repo. The next step is to get it to upload that directory to GitHub.
Add your authentication information to ~/.m2/settings.xml so that the github site-maven-plugin can push to GitHub:
<!-- NOTE: MAKE SURE THAT settings.xml IS NOT WORLD READABLE! -->
<settings>
<servers>
<server>
<id>github</id>
<username>YOUR-USERNAME</username>
<password>YOUR-PASSWORD</password>
</server>
</servers>
</settings>
(As noted, please make sure to chmod 700 settings.xml to ensure no one can read your password in the file. If someone knows how to make site-maven-plugin prompt for a password instead of requiring it in a config file, let me know.)
Then tell the GitHub site-maven-plugin about the new server you just configured by adding the following to your pom:
<properties>
<!-- github server corresponds to entry in ~/.m2/settings.xml -->
<github.global.server>github</github.global.server>
</properties>
Finally, configure the site-maven-plugin to upload from your temporary staging repo to your mvn-repo branch on Github:
<build>
<plugins>
<plugin>
<groupId>com.github.github</groupId>
<artifactId>site-maven-plugin</artifactId>
<version>0.11</version>
<configuration>
<message>Maven artifacts for ${project.version}</message> <!-- git commit message -->
<noJekyll>true</noJekyll> <!-- disable webpage processing -->
<outputDirectory>${project.build.directory}/mvn-repo</outputDirectory> <!-- matches distribution management repository url above -->
<branch>refs/heads/mvn-repo</branch> <!-- remote branch name -->
<includes><include>**/*</include></includes>
<repositoryName>YOUR-REPOSITORY-NAME</repositoryName> <!-- github repo name -->
<repositoryOwner>YOUR-GITHUB-USERNAME</repositoryOwner> <!-- github username -->
</configuration>
<executions>
<!-- run site-maven-plugin's 'site' target as part of the build's normal 'deploy' phase -->
<execution>
<goals>
<goal>site</goal>
</goals>
<phase>deploy</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
The mvn-repo branch does not need to exist, it will be created for you.
Now run mvn clean deploy again. You should see maven-deploy-plugin "upload" the files to your local staging repository in the target directory, then site-maven-plugin committing those files and pushing them to the server.
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building DaoCore 1.3-SNAPSHOT
[INFO] ------------------------------------------------------------------------
...
[INFO] --- maven-deploy-plugin:2.5:deploy (default-deploy) # greendao ---
Uploaded: file:///Users/mike/Projects/greendao-emmby/DaoCore/target/mvn-repo/com/greendao-orm/greendao/1.3-SNAPSHOT/greendao-1.3-20121223.182256-3.jar (77 KB at 2936.9 KB/sec)
Uploaded: file:///Users/mike/Projects/greendao-emmby/DaoCore/target/mvn-repo/com/greendao-orm/greendao/1.3-SNAPSHOT/greendao-1.3-20121223.182256-3.pom (3 KB at 1402.3 KB/sec)
Uploaded: file:///Users/mike/Projects/greendao-emmby/DaoCore/target/mvn-repo/com/greendao-orm/greendao/1.3-SNAPSHOT/maven-metadata.xml (768 B at 150.0 KB/sec)
Uploaded: file:///Users/mike/Projects/greendao-emmby/DaoCore/target/mvn-repo/com/greendao-orm/greendao/maven-metadata.xml (282 B at 91.8 KB/sec)
[INFO]
[INFO] --- site-maven-plugin:0.7:site (default) # greendao ---
[INFO] Creating 24 blobs
[INFO] Creating tree with 25 blob entries
[INFO] Creating commit with SHA-1: 0b8444e487a8acf9caabe7ec18a4e9cff4964809
[INFO] Updating reference refs/heads/mvn-repo from ab7afb9a228bf33d9e04db39d178f96a7a225593 to 0b8444e487a8acf9caabe7ec18a4e9cff4964809
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 8.595s
[INFO] Finished at: Sun Dec 23 11:23:03 MST 2012
[INFO] Final Memory: 9M/81M
[INFO] ------------------------------------------------------------------------
Visit github.com in your browser, select the mvn-repo branch, and verify that all your binaries are now there.
Congratulations!
You can now deploy your maven artifacts to a poor man's public repo simply by running mvn clean deploy.
There's one more step you'll want to take, which is to configure any poms that depend on your pom to know where your repository is. Add the following snippet to any project's pom that depends on your project:
<repositories>
<repository>
<id>YOUR-PROJECT-NAME-mvn-repo</id>
<url>https://github.com/YOUR-USERNAME/YOUR-PROJECT-NAME/raw/mvn-repo/</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
</snapshots>
</repository>
</repositories>
Now any project that requires your jar files will automatically download them from your github maven repository.
Edit: to avoid the problem mentioned in the comments ('Error creating commit: Invalid request. For 'properties/name', nil is not a string.'), make sure you state a name in your profile on github.
Don't use GitHub as a Maven Repository.
Edit: This option gets a lot of down votes, but no comments as to why. This is the correct option regardless of the technical capabilities to actually host on GitHub. Hosting on GitHub is wrong for all the reasons outlined below and without comments I can't improve the answer to clarify your issues.
Best Option - Collaborate with the Original Project
The best option is to convince the original project to include your changes and stick with the original.
Alternative - Maintain your own Fork
Since you have forked an open source library, and your fork is also open source, you can upload your fork to Maven Central (read Guide to uploading artifacts to the Central Repository) by giving it a new groupId and maybe a new artifactId.
Only consider this option if you are willing to maintain this fork until the changes are incorporated into the original project and then you should abandon this one.
Really consider hard whether a fork is the right option. Read the myriad Google results for 'why not to fork'
Reasoning
Bloating your repository with jars increases download size for no benefit
A jar is an output of your project, it can be regenerated at any time from its inputs, and your GitHub repo should contain only inputs.
Don't believe me? Then check Google results for 'dont store binaries in git'.
GitHub's help Working with large files will tell you the same thing. Admittedly jar's aren't large but they are larger than the source code and once a jar has been created by a release they have no reason to be versioned - that is what a new release is for.
Defining multiple repos in your pom.xml slows your build down by Number of Repositories times Number of Artifacts
Stephen Connolly says:
If anyone adds your repo they impact their build performance
as they now have another repo to check artifacts against... It's not a big
problem if you only have to add one repo... But the problem grows and the next
thing you know your maven build is checking 50 repos for every artifact and
build time is a dog.
That's right! Maven needs to check every artifact (and its dependencies) defined in your pom.xml against every Repository you have defined, as a newer version might be available in any of those repositories.
Try it out for yourself and you will feel the pain of a slow build.
The best place for artifacts is in Maven Central, as its the central place for jars, and this means your build will only ever check one place.
You can read some more about repositories at Maven's documentation on Introduction to Repositories
You can use JitPack (free for public Git repositories) to expose your GitHub repository as a Maven artifact. Its very easy. Your users would need to add this to their pom.xml:
Add repository:
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
Add dependency:
<dependency>
<groupId>com.github.User</groupId>
<artifactId>Repo name</artifactId>
<version>Release tag</version>
</dependency>
As answered elsewhere the idea is that JitPack will build your GitHub repo and will serve the jars. The requirement is that you have a build file and a GitHub release.
The nice thing is that you don't have to handle deployment and uploads. Since you didn't want to maintain your own artifact repository its a good match for your needs.
Since 2019 you can now use the new functionality called Github package registry.
Basically the process is:
generate a new personal access token from the github settings
add repository and token info in your settings.xml
deploy using
mvn deploy -Dregistry=https://maven.pkg.github.com/yourusername -Dtoken=yor_token
Another alternative is to use any web hosting with webdav support. You will need some space for this somewhere of course but it is straightforward to set up and a good alternative to running a full blown nexus server.
add this to your build section
<extensions>
<extension>
<artifactId>wagon-webdav-jackrabbit</artifactId>
<groupId>org.apache.maven.wagon</groupId>
<version>2.2</version>
</extension>
</extensions>
Add something like this to your distributionManagement section
<repository>
<id>release.repo</id>
<url>dav:http://repo.jillesvangurp.com/releases/</url>
</repository>
Finally make sure to setup the repository access in your settings.xml
add this to your servers section
<server>
<id>release.repo</id>
<username>xxxx</username>
<password>xxxx</password>
</server>
and a definition to your repositories section
<repository>
<id>release.repo</id>
<url>http://repo.jillesvangurp.com/releases</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
Finally, if you have any standard php hosting, you can use something like sabredav to add webdav capabilities.
Advantages: you have your own maven repository
Downsides: you don't have any of the management capabilities in nexus; you need some webdav setup somewhere
As an alternative, Bintray provides free hosting of maven repositories. That's probably a good alternative to Sonatype OSS and Maven Central if you absolutely don't want to rename the groupId. But please, at least make an effort to get your changes integrated upstream or rename and publish to Central. It makes it much easier for others to use your fork.
If you have only aar or jar file itself, or just don't want to use plugins - I've created a simple shell script. You can achieve the same with it - publishing your artifacts to Github and use it as public Maven repo.
I'd like to add another alternative, a Gradle plugin I've been working on lately: magik.
Basically it allows to publish directly on a github repository acting as a maven repository.
I came here looking to do the same thing, unlitmately host my Maven repository for free, but after more research I ended up here:
https://jfrog.com/start-free/
The setup was quite strightforward, has a good free tier which will serve me for the forseeable future, and has additional (paid for) upgrades which may well come in handy in the future.
So far I am very pleased indeed !

Resources