Distributing application with its Maven POM only - java

Is it possible to distribute my application with its POM only ?
I have deployed my application in a remote repository and I think it would be nice if I can distribute only its POM, instead of asking the users to download the complete source first and use the POM to build the application afterwards.
The idea is that users would be able to install the application using the POM and a single Maven command.
I tried adding to the POM a downloadURL in a distributionManagement section without success. Here my experiment:
<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>aGroupId</groupId>
<artifactId>anArtifactId</artifactId>
<version>0.0.1</version>
<distributionManagement>
<downloadUrl>anURL</downloadUrl>
</distributionManagement>
<repositories>
<repository>
<id>someId</id>
<url>anURL</url>
</repository>
</repositories>
</project>
Thanks in advance for any feedback

If you're distributing source, then you should look at the bootstrap POM method: http://maven.apache.org/scm/maven-scm-plugin/examples/bootstrapping-with-pom.html
where the 'scm' element is key. The user has only to run scm:bootstrap to then receive the project source tree from which to build the project.
-tim

You can use the dependency:get mojo to download an artifact to a specified location:
mvn dependency:get -Dartifact=<groupid>:<artifactid>:<version> /
-Ddest=path/to/destination.jar

Related

How to "bootstrap" parent POM in GCP Artifact Registry

I followed the instructions to configure a maven client to use an Artifact Registry. I was able to deploy my root pom to it successfully; however, when I have a separate project that inherits from that root pom, it fails to build because it doesn't know where to find the root pom. This makes sense: the child project has no way of knowing that the parent pom is to be found in a random Artifact Registry repo. What is the standard practice for this?
What i've done before is in every programmer's computer, configure the <repository> in their settings.xml but this doesn't scale well + it needs human intervention + it's very cumbersome when dealing with CI since now you need to configure the settings.xml of the build robot. Considering there's so many CI systems nowadays I imagine there's a convention by now. Is there a better way to accomplish this? some way that's committed in the repo and where everything works right out of the box? git clone... mvn package... done. I ask specifically about Artifact Registry because it doesn't use a static username/password but uses the maven wagon to authenticate
One potential solution is to not put the <repository> in the root pom but in every project's pom but that leads to a lot of duplication since the config + the wagon is pretty verbose
Assuming your child and parent share a common .mvn/ folder, you can add:
.mvn/extensions.xml:
<extensions xmlns="http://maven.apache.org/EXTENSIONS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/EXTENSIONS/1.0.0 http://maven.apache.org/xsd/core-extensions-1.0.0.xsd">
<!--This has to be declared here in order to allow child modules to be able to fetch older parent POMs.-->
<extension>
<groupId>com.google.cloud.artifactregistry</groupId>
<artifactId>artifactregistry-maven-wagon</artifactId>
<version>2.1.1</version>
</extension>
<!--project-settings-extension allows using project-specific .mvn/settings.xml-->
<extension>
<groupId>com.github.gzm55.maven</groupId>
<artifactId>project-settings-extension</artifactId>
<version>0.1.1</version>
</extension>
</extensions>
.mvn/settings.xml (don't forget to use your actual artifactregistry URL):
<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 https://maven.apache.org/xsd/settings-1.0.0.xsd">
<profiles>
<profile>
<id>default</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<repositories>
<!--This has to be declared here in order to allow child modules to be able to fetch older parent POMs.-->
<repository>
<id>cloud-artifacts</id>
<url>artifactregistry://...</url> <!--use actual full URL here-->
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
</snapshots>
</repository>
</repositories>
</profile>
</profiles>
</settings>
The repository in settings.xml informs Maven to consider that location when searching for artifacts. The artifactregistry-maven-wagon extension allows Maven to access artifacts via the artifactregistry:// protocol.
The other extension (com.github.gzm55.maven) causes Maven to look at the project-specific settings.xml file (you could also just pass --settings=<path to file>, perhaps in .mvn/maven.config, but that would override any user settings).

How to configure distinct distributionManagement repositories to plugins and libs?

I'm trying to configure the distributionManagement section of a parent POM to enable the upload of libs and plugins to distinct Artifactory repositories, but maven 3 only supports one section of distributionManagement configuration.
As I use differente repositories to download plugins and libs and it's not usable to create one parent POM to each type of artifact, is it possible to configure distinct repositories to let Artifactory, or simply maven, identify the type of artifact and deploy to the correct repository?
Here is this current pom:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ornanization</groupId>
<artifactId>corporative-parent</artifactId>
<packaging>pom</packaging>
<distributionManagement>
<repository>
<id>artifactoryRelease</id>
<name>artifactory-libs-releases<name>
<url>${artifactory.url}/libs-release-local</url>
</repository>
<snapshotRepository>
<id>artifactorySnapshot</id>
<name>artifactory-libs-snapshots</name>
<url>${artifactory.url}/libs-snapshot-local</url>
</snapshotRepository>
</distributionManagement>
</project>
And this is the entry I'd like to add:
<distributionManagement>
<repository>
<id>artifactoryRelease</id>
<name>artifactory-plugins-releases</name>
<url>${artifactory.url}/plugins-release-local</url>
</repository>
<snapshotRepository>
<id>artifactorySnapshot</id>
<name>artifactory-plugins-snapshots</name>
<url>${artifactory.url}/plugins-snapshot-local</url>
</snapshotRepository>
</distributionManagement>
p.s.: as stated on this page of the Artifactory's User Guide, it's not possible to "deploy build artifacts to remote or virtual repositories" only to local repositories, so it's not possible to let Artifactory's layout management identify the artifact's type.
Just don't use the <distributionManagement> and use the Artifactory Maven Plugin instead.
The <repoKey> tag of the configuration allows you to use variables (both environment and project defined). Just define a variable that will represent plugin and lib repositories and set the values in the corresponding projects.
Also, you'll get the full Build Info BOM on deployment as a bonus.
Thanks to #JBaruch tip to "define a variable that will represent plugin and lib repositories", I first did a research on maven profiles to activate from a variable and realize that it's possible to activate a profile if a certain condition is matched, so I ended up with the following solution:
<profile>
<id>plugins-deploy-artifactory</id>
<activation>
<file>
<exists>target/classes/META-INF/maven/plugin.xml</exists>
</file>
</activation>
<distributionManagement>
<repository>
<id>artifactoryRelease</id>
<name>artifactory-corporativo-releases</name>
<url>${artifactory.url}/plugins-release-local</url>
</repository>
<snapshotRepository>
<id>artifactorySnapshot</id>
<name>artifactory-corporativo-snapshots</name>
<url>${artifactory.url}/plugins-snapshot-local</url>
</snapshotRepository>
</distributionManagement>
</profile>
So when the artifact is a plugin, the profile above is activated, otherwise, the default distributionManagement is used.

Maven Release Patterns

I'm new to maven, and trying to understand how to release my project. I have the following project setup in svn:
trunk
|-deployer
| |-pom.xml
|-webapp
| |-pom.xml
|-utils
|-pom.xml
While developing webapp, I always want to develop against the latest snapshot version of utils, so I declare the dependency on utils in webapp/pom.xml via:
com.company
utils
1.0-SNAPSHOT
Webapp itself is also currently versioned at version 1.0-SNAPSHOT. It's pom.xml has the declaration:
<artifactId>webapp</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>Sample Webapp</name>
So everything is working great, but now I want to release my software. In deployer, I have the following in pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.company</groupId>
<artifactId>deployer</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>Project Release</name>
<modules>
<module>externals/webapp</module>
</modules>
<properties>
<url.svn>http://<my-server>/<project>/trunk</url.svn>
</properties>
<scm>
<connection>scm:svn:${url.svn}</connection>
</scm>
<build>
<plugins>
<plugin>
<artifactId>maven-release-plugin</artifactId>
<version>2.3</version>
<configuration>
<tagBase>
http://<my-server>/<project>/tags
</tagBase>
</configuration>
</plugin>
</plugins>
</build>
<distributionManagement>
<repository>
<id>Releases</id>
<name>Releases</name>
<url>http://<nexus-server>/nexus/content/repositories/releases</url>
</repository>
<snapshotRepository>
<id>Snapshots</id>
<name>Snapshots</name>
<url>http://<nexus-server>/nexus/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>
</project>
Within the deployer folder itself I have a folder called "externals" which has an svn-externals set to check out my webapp project (I added this because maven complained about not being able to find it), so my modules path should be correct.
Questions
1.) I want to release a version of my web app, but when I run a mvn release:prepare and mvn release:perform in my deployer project, my only tangible output is my trunk tagged in svn and a pom uploaded to my nexus repository. This makes sense in that my deployer artifact packaging is type "pom", but it also doesn't get the job done of getting me a war of my webapp (I should note here that if a do a release in the webapp project by itself though, that I will get the war). I need to release multiple modules, and so I thought I could use maven aggregation from the deployer project to accomplish this, but it doesn't seem to be working.
2.) Is there a better way to achieve what I am trying to do?
Thank you for any insights you can provide.
You should run the maven-release-plugin against each module that you intend to release. I've never seen someone have a special "deployer" module that releases the other modules, this is not how things are commonly done.
Normally to release the webapp module you would run the commands against the webapp module, and to release the utils module you would run the commands against the utils module.
If you have a parent module that ties webapp and util together then I believe you can just run the release commands against that.
As matt b says, simply adding a maven-release-plugin entry at the top pom will probably do what you want. If you want to collect several artifacts into a proper release bundle, you want to create a module for this, but then you want to look at the maven assembly plugin. It can collect various jars (wether from modules or external dependencies) and resources into a directory, zip file or similar.

Can I put the packaged file into another directory?

I am wondering if I can put a packaged JAR or WAR into another directory using Maven. How can I do that?
You could specify a directory as your delivery location:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.myspotontheweb.demo</groupId>
<artifactId>demo</artifactId>
<version>1.0</version>
<distributionManagement>
<repository>
<id>internal.repo</id>
<name>MyCo Internal Repository</name>
<url>file:///home/me/path/to/my/repo</url>
</repository>
</distributionManagement>
</project>
Just run maven as follows
mvn clean deploy
I suspect this is not what you're looking for...It's kinda pointless.... Running the install goal places the same artifact in the following default location
$HOME/.m2/repository
Some further guidance on why you want to do this might furnish a better answer

Is there a way to make Maven download snapshot versions automatically?

So I have a project that depends on a snapshot version of another project. The dependency is:
<dependency>
<groupId>org.oop</groupId>
<artifactId>oop</artifactId>
<version>0.9.9-SNAPSHOT</version>
</dependency>
For the oop project, I did do a 'mvn clean deploy', so the snapshot version should be somewhere in the maven central repository. But when I do a mvn clean install, the snapshot dependency above cannot be resolved and I get this:
Missing:
1) org.oop:oop:jar:0.9.9-SNAPSHOT
Try downloading the file manually from the project website.
Then, install it using the command:
mvn install:install-file -DgroupId=org.oop -DartifactId=oop -Dversion=0.9.9-SNAPSHOT -Dpackaging=jar -Dfile=/path/to/file
Alternatively, if you host your own repository you can deploy the file there:
mvn deploy:deploy-file -DgroupId=org.oop -DartifactId=oop -Dversion=0.9.9-SNAPSHOT -Dpackaging=jar -Dfile=/path/to/file -Durl=[url] -DrepositoryId=[id]
Is there a way to make maven download the snapshot automatically? I must be missing something here.
EDIT1: On my settings.xml I have:
<server>
<id>sonatype-nexus-snapshots</id>
<username>XXXXXX</username>
<password>XXXXXX</password>
</server>
<server>
<id>sonatype-nexus-staging</id>
<username>XXXXXX</username>
<password>XXXXXX</password>
</server>
EDIT2:
Just add this to your ~/.m2/settings.xml:
<profiles>
<profile>
<id>allow-snapshots</id>
<activation><activeByDefault>true</activeByDefault></activation>
<repositories>
<repository>
<id>snapshots-repo</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases><enabled>false</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
</repository>
</repositories>
</profile>
</profiles>
To update snapshots, try with the -U option
-U,--update-snapshots Forces a check for updated
releases and snapshots on remote
repositories
However, you said:
I did do a 'mvn clean deploy', so the snapshot version should be somewhere in the maven central repository.
This is just not possible, your snapshot is going somewhere else. If I do a mvn clean deploy without configuring my personal repository I get:
Deployment failed: repository element was not specified in the POM inside distributionManagement element or in -DaltDeploymentRepository=id::layout::url parameter
To enable deployment, there is some configuration to be added to pom.xml, like for instance:
<distributionManagement>
<!-- Publish versioned releases here -->
<repository>
<id>myrepo</id>
<name>My releases</name>
<url>http://nexus.mycompany.com/nexus/content/repositories/releases</url>
</repository>
<!-- Publish snapshots here -->
<snapshotRepository>
<id>myrepo</id>
<name>my snapshots</name>
<url>http://nexus.mycompany.com/nexus/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>
<repositories>
<repository>
<id>myrepo</id>
<name>My Public Repository</name>
<url>http://nexus.mycompany.com/nexus/content/groups/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
Maven would try to download the snapshot automatically and indeed it does (as your error indicates). By default, Maven will look for newer snapshot versions once a day, but you can change that interval in your snapshot repository config (e.g. in settings.xml):
<updatePolicy>interval:5</updatePolicy>
This will make maven check every 5 minutes (if you build that often). Alternatively, you could use the -U or --update-snapshots option, to force the check manually.
However, it can't find the dependency. Could you post your repo settings and artifact config for the snapshot dependency?
Is the org.oop:oop:jar:0.9.9-SNAPSHOT artifact in your repository?
... so the snapshot version should be somewhere in the maven central repository.
No it isn't. I tried to look it up, but couldn't find it. Afaik, there's some staging mechanism, so maybe your settings are just wrong. But normally, as the others already said, you'd go and use your own repository manager like Artifactory or Nexus.
Does that dependency exists in your repository? (in pom.xml or settings.xml)?
Looks like not. By the way, take a look at your config, just you are not using -o (offline). Also you can use -U to refresh snapshots.
You can either
use a parent project which builds all your snapshots, or
deploy your snapshots to your maven build server (nexus/archiva/..) using e.g., mvn:deploy
Let's clear up terminology a bit to make sure there is no misunderstanding.
"Maven Central" (http://search.maven.org/) is a global site where you only find releases. Central doesn't accept snapshots so deploying there should give you an error.
You probably mean your local/company wide maven proxy/cache. These can also be configured to reject snapshot versions. In case of Nexus, you can also define more complex rules. In my case, I had an issue there which gave no error during mvn deploy but I could see an error in the server's logs.
Try to follow the data: Enable debug (mvn -X) to see where Maven uploads the data. Then check the server to see whether the artifacts were really uploaded. Check the server's logs for errors.
Also note that snapshot dependencies are only refreshed once a day; so this won't work:
PC #1: mvn install -> Error missing dependency
PC #2: mvn deploy
PC #1: mvn install -> Dependency is still missing because of "update once per day" policy
Try mvn install -U to force Maven to refresh its cached metadata.
I hit the issue of snapshots not updating even when setting -U on the command line. For me the issue was my client was Maven 3 and the server was Maven 2, and in Maven 3 unique snapshots are no longer supported. We had to create a new repository with timestamped snapshots to support the 3.xx clients.

Categories

Resources