How to update maven local repository with newer artifacts from a remote repository? - maven

My maven module A has a dependency on another maven module B provided by other people. When I run "mvn install" under A for the first time, maven downloads B-1.0.jar from a remote repository to my local maven repository. My module A builds fine.
In the mean time, other people are deploying newer B-1.0.jar to the remote repository. When I run "mvn install" under A again, maven does not download the newer B-1.0.jar from the remote repository to my local repository. As a result, my module A build fails due to API changes in B-1.0.jar.
I could manually delete B-1.0.jar from my local repository. Then maven would download the latest B-1.0.jar from the remote repository the next time when I run "mvn install".
My question is how I can automatically let maven download the latest artifacts from a remote repository. I tried to set updatePolicy to "always". But that did not do the trick.

Maven never re-downloads releases - 1.0 is considered final and new releases should use a new version.
If the module B is still under development, you should use the version 1.0-SNAPSHOT - snapshots are a special Maven version that will check for updates, and when deployed is stored with the timestamp and build number for tracking.

I agree with Brett, above: new releases should use new versions. For your case, snapshots are probably the best solution but something else that might also be helpful is to use dependency version ranges.
Thereby you can specify a version of
(1.0,)
stating that you accept any version greater than 1.0.
or
[1.1.1,1.1.7]
accepting anything between (including) versions 1.1.1 and 1.1.7.
The notation follows standard math interval syntax where
[ = inclusion in the interval
( = exclusion from the interval
(in school, I always thought of the square brackets as "holding" that element in, while the softer parenthesis "let it go")
This can be helpful in cases where your dependencies are still under frequent development and you don't want to rely on new snapshots that might be less stable and more likely to break your code. You can specify the safe ranges and adjust the boundaries up or down, as appropriate, over time

Related

Maven build on Jenkins - upstream version range resolves to version being built in a concurrent job

We have a Jenkins build which in it's initial stage tries to determine the latest deployed version of some dependencies via version ranges, which are also built by that same Jenkins instance. Each build is for several artifacts, all with a shared version, so we want to select the latest version which has been completed. We do this by using a special pom which has dependencies on specific poms - these are deployed last by the other builds.
The issue is that if one of the other builds is running, but has not yet deployed the pom, maven's version range resolution winds up selecting the version for the build in progress and then fails as some of the dependencies haven't been built yet.
This isn't a downstream build kicked off by the dependency. In any case, we've tried the "Enable isolated resolution for downstream builds" and "Resolve artifacts from Artifactory" but neither have helped.
If the project is a normal UI "maven project" then there is a Use private Maven repository checkbox that uses the workspace specific maven repository cache
Normally, Jenkins uses the local Maven repository as determined by Maven — the exact process seems to be undocumented, but it's ~/.m2/repository and can be overridden by in ~/.m2/settings.xml (see the reference for more details.)
This normally means that all the jobs that are executed on the same node shares a single Maven repository. The upside of this is that you can save the disk space, but the downside of this is that sometimes those builds could interfere with each other. For example, you might end up having builds incorrectly succeed, just because your have all the dependencies in your local repository, despite that fact that none of the repositories in POM might have them.
There are also some reported problems regarding having concurrent
Maven processes trying to use the same local repository.
When this option is checked, Jenkins will tell Maven to use
$WORKSPACE/.repository as the local Maven repository. This means each
job will get its own isolated Maven repository just for itself. It
fixes the above problems, at the expense of additional disk space
consumption.
When using this option, consider setting up a Maven artifact manager
so that you don't have to hit remote Maven repositories too often.
If you'd prefer to activate this mode in all the Maven jobs executed
on Jenkins, refer to the technique described here.
If it's a pipeline job they a mavenLocalRepo setting see: https://plugins.jenkins.io/pipeline-maven/
If it was a freestyle job, your only choice to do what that option does by hand
By using this option, Jenkins will tell Maven to use a custom path for the build as the local Maven repository by using -Dmaven.repo.local
If specified as a relative path then this value will be resolved against the workspace root and not the current working directory.
ie. $WORKSPACE/.repository if .repository value is specified.
The issue is due to the Jenkins maven local repository - it looks like in the current configuration this is shared between the builds. Thus, the in-flight build manages to pick up installed poms that haven't yet been deployed.
We solved this by adding -Dmaven.local.repo=${WORKSPACE}/.m2/repository for when we resolve the version ranges - this way the build is isolated from the other concurrent builds for this stage.

Jenkins - get latest artifact version from remote repository

I'm trying to create a deploy job in Jenkins. Up until now I was building my artifact via the maven install goal and then deploying it on the application server with a shell script. However, I'd now like to skip the install part and just get the artifact from my nexus repository.
I know there is the maven dependency:get which I can use to retrieve the artifact from the repository but is there any way I can make sure I'll get the latest version without passing it as a build parameter?
You have different options:
1) Use the Repository Connector Plugin. With this plugin, you get an additional "Artifact Resolver" build step, where you can download an artifact from a centrally configured (Manage Jenkins) repository to the workspace of your deploy job (with different options like renaming etc).
If you use the version LATEST, you always get the latest version. Likewise, you can use RELEASE for the latest release version or ranges like [1.0,1.1).
There are two caveats however:
In the newest version of the plugin, LATEST is broken (see https://issues.jenkins-ci.org/browse/JENKINS-20263), so you need to use version 0.8.2 for now).
You should manually fingerprint the downloaded artifact, since this is not automatically done right now.
2) Use dependency:get as suggested, but use LATEST or RELEASE as above. However, I do not think this is a really elegant solution. (if you simply use SNAPSHOTs with the same base version, follow khmarbaise's advice and simply add -U to the commandline)
3) Use the Maven Deployment Linker Plugin plugin, which is a rather elegant alternative, since you can copy artifacts from other jobs like Copy-Artifact, but they are still retrieved from your Artifact repository (thus you do not waste diskspace and time). The largest problem with that plugin is that it currently does not support authentification.

maven can't find my local artifacts

I can't seem to run mvn -o package because it complains with
The repository system is off line but the artifact
com.liferay.portal:util-bridges:jar:6.1.20 is not available in the
local repository.
But I checked my local repository and that artifact does exist there. I also tried the solution of setting updatePolicy to never in the settings.xml file but that failed to work.
Prior to Maven 3.0.x, Maven did not track the origin of files in the local repository.
This could result in build issues, especially if you were building something that listed the (now dead) very borked java.net2 repository... Not only did that repository change released artifacts (extremely bad and evil practice) but it also published artifacts at the same coordinates as artifacts on central but with different content (unbelievably evil)
So you could have the build work (because you had commons-io:commons-io:2.0 from central) wipe your local repo and the build fails (because you now get commons-io:commons-io:2.0 from java.net2 which was a completely different artifact with different dependencies in the pom) or vice versa.
The above situation is one of the drivers for using a maven repository manager, because that allows you to control the subset of a repository that you expose downstream and the order in which artifacts are resolved from multiple repositories (usually referred to as routing rules)
In any case, when maven switched to Aether as the repository access layer, the decision was made to start tracking where artifacts come from.
So with Maven 3.0.x, when an artifact is downloaded from a repository, maven leaves a _maven.repositories file to record where the file was resolved from. If you are building a project and the effective list of repositories does not include the location that the artifact was resolved from, then Maven decides that it is as if the artifact was not in the cache, and will seek to re-resolve the artifact...
There are a number of bugs in 3.0.x though... The most critical being how offline is handled... Namely: when offline, maven 3.0.x thinks there are no repositories, so will always find a mismatch against the _maven.repositories file!!!
The workaround for Maven 3.0.x is to delete these files from your local cache, eg
$ find ~/.m2/repository -name _maven.repositories -exec rm -v {} \;
The side effect is that you loose the protections that Maven 3.0.x is trying to provide.
The good news is that Maven 3.1 will have the required fix (if we can ever get our act together and get a release out the door)
With Maven 3.1 when in offline mode the _maven.repositories file is (semi-)ignored, and there is also an option to ignore that file for online builds (referred to as legacy mode)
At this point in time (June 1st 2013) the 4th attempt to cut a release that meets the legal and testing requirements is in progress... So, assuming that the 4th time is lucky, I would hope to see 3.1.0-alpha-1 released in 3-4 days time... But it could be longer given that we want to give the changes in 3.1 enough time to soak to ensure uses builds don't break (there was a change in an API exposed (by accident-ish - the API is needed by the site and dependency plugin) that plugin authors have depended on (even though they shouldn't have) so there is potential, though we think we have all the bases covered)
Hope that answers your question (and maybe a few more you didn't know you had ;-) )
I also had to remove _remote.repositories in the same way as the _maven.repositories described above. I'm using Maven 3.1.1
find ~/.m2/repository -name _remote.repositories -exec rm -v {} \;
I had this issue when i was using apache-maven-3.0.4, the issue is gone right after i move to apache-maven-3.3.1.
I had this issue in Ubuntu Linux when I've installed local artifacts via a shell script. The solution was to delete the local artifacts and install them again "manually" - calling mvn install:install-file via terminal.

maven release perform failed

Today while doing the release of our project, the release:perform command failed in between as our nexus was having intermittent issues. The release command only able to upload one pom file to nexus.
Now, the nexus issue is resolved and I am trying to do the release, it fails as the pom file already exists and its not the snapshot version and we don't have access to nexus so that I can delete that file and start over again.
Is there any way I can pass an argument so that release:perform should continue if the file is already there and ignore this but continue with uploading the rest.
I have looked for options of such type but didn't find anything.
My last resource would be to start the release again, which will bump the version number, but would like to understand if there is any other approach where in I don't need to bump the version.
I am using maven 2.2.1
Here's how I have handled this in the past. The release:perform command does a checkout of the tag from your SCM provider (e.g. SVN). This is done in the target/checkout directory of that project - whatever is there should be an exact copy of the released tag, so it will have the right version number in the pom files etc.
If you move to that directory (target/checkout in the directory where you started the release), you can simply do a mvn deploy there and it should compile and package that version, and then upload it to your Nexus instance.
If you don't have the target/checkout directory, you can check out the Tag created as part of the release:prepare phase from your SCM system to a fresh directory and run mvn deploy there.
Since the tag in your SCM has already been created, the only thing that's left is really compiling, packaging and deploying the release, which is exactly what mvn deploy should do.
If you have provided additional parameters (e.g. for activating profiles) for the build during the call to mvn release:perform, you will have to provide these as well when you run mvn deploy.
Using this approach, your version number will not have to change, it can stay the same, since you're just uploading what has already been tagged as part of mvn release:prepare.
My advice would be for you to request from the admins that the old artifact be removed. You can either re-deploy the code from the tag by checking it out and simply doing
mvn deploy
Or rolling back your release:
mvn release:rollback
And re-doing it as usual.
It is essential to remove the old artifact from the remote repository, if the sizes do not match. Release repositories do not allow the redeployment of artifacts, unless this has been explicitly switched on on the server side.
Furthermore, #nwinkler's answer is also quite good.

Using maven, how can I deploy artifacts that I have already compiled with a different version?

I have a continuous integration build process where each change gets compiled and deployed as a Maven snapshot. When a version is compiled and tested that people are happy with, I want to be able to deploy this to our local Maven repository with a release version.
"The Maven way" to do this would be to take the source again, set a version (versions:set etc), compile and test it all over again then deploy the resulting artifacts. As this process takes some time, I would prefer not to go through all the steps again.
Is there a way of taking the artifacts produced by the first compile step, update the version and deploy them as is without recompiling?
What you believe to be "Maven Way" is not necessarily true. However if you do want to deploy an arbitrary jar as a maven artifact of a different group / name / version you can do so using maven deploy plugin:
mvn deploy:deploy-file -Durl=/path/to/remote/repository -Dfile=/path/to/myjar-1.22.jar -DgroupId=somegroup -DartifactId=yourjar -Dpackaging=jar -Dversion=1.23
The above example will deploy myjar-1.22 as yourjar-1.23 into remote repository.
However you should be cautious about this. Often the original version information is used inside the project itself (as a jar metadata etc)
In my opinion the best way is not to change the version number, but stick to it all the way into the software lifecycle. Utilize source control revision / build number so you always get a unique version label. For example, name your artifact myjar-1.0.3345.23.jar where 1.0 is your major/minor version, 3345 is your source control revision number, and 23 is the build number

Resources