How to set up Maven project to optionally generate signature files - java

I maintain a small Java component published in Maven Central. In order to successfully publish the artifact, pgp/gpg signature files are required for all the artifacts. Following the directions here: https://central.sonatype.org/pages/apache-maven.html#gpg-signed-components, I can add this plugin to my pom.xml like this no problem.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
...
and I attach it to the verify or install phase. Now, when I run: "mvn install" or "mvn deploy" the .asc files are generated automatically as desired. Note: you also have to have your pgp/gpg machinery installed and configured properly for this to work.
This works OK for me as the artifact maintainer, but if someone else wants to clone my source code, modify it, and then run mvn install so they can make a locally modified version of the component available to other projects of theirs, they have to have all this pgp/gpg machinery setup properly too, which can be a pain. And they likely don't care about having signature files.
My question is, is there a recommended pom setup so the component maintainer can generate the .asc signature files when needed for a deployment (e.g., to Maven Central), but normal usage of Maven commands don't require signature generation?
I imagine I could use a profile in my pom to handle this. I did figure out a solution, which is pretty simple. Rather than adding the maven-gpg-plugin to my pom, I figured out I can actually just do this:
mvn clean install org.apache.maven.plugins:maven-gpg-plugin:sign deploy
This cleans everything, creates and installs all the artifacts locally, signs all the generated artifacts, and then deploys all the generated artifacts, including the signature files to the deployment target.
This does exactly what I want in 1 line without a pom modification, which is pretty cool. But are there other 'better' ways? Either way, I figured posting this way to do this might be helpful to others.

maven profile
One way using maven-gpg-plugin conditional it is put configuration of maven-gpg-plugin in profile.
You can simplify your profile by only add one property for skip / don't skip maven-gpg-plugin
Your project can look like:
<project ...>
<properties>
<gpg.skip>true</gpg.skip><!-- by default skip gpg -->
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<configuration>
<!-- ... -->
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>release</id>
<properties>
<gpg.skip>false</gpg.skip>
</properties>
</profile>
</profiles>
</project>
another plugin
You can also consider use another plugin for making signatures, eg: https://www.simplify4u.org/sign-maven-plugin/ sign-maven-plugin by default skips execution if private key not exist on running system.
Another feature of sign-maven-plugin is that don't need external software like gpg to make signature.

gpp.skip property
In my poms I set the gpp.skip property to true:
<properties>
<gpg.skip>true</gpg.skip>
</properties>
Its evaluated by the maven gpg plugin in the way, that signing is skipped by default, e.g.:
mvn install
To enable signing, you can set gpp.skip to false within pom.xml. But better you do it on the command line, so you don't have to modify your pom all the time:
mvn install -Dgpg.skip=false
You can also skip setting the property within the pom and skip signing like this:
mvn install -Dgpg.skip=true
But this way you (and other people working with your project) have to add this all the time to avoid signing. I find it more convenient when signing is turned off by default, as in the first solution. And I guess that's what you want.

Related

How to build same source code twice with different dependency version, in both Maven and Eclipse?

I would like to build two different versions of a custom SonarQube (SQ) plugin; one for SonarQube 6.7.x LTS release, one for the latest 7.6 release. At the moment, I have a Maven structure similar to the following:
parent
common: Common code used by both tool and both plugin versions, doesn't use SQ API
tool: Some related command-line utility, doesn't use SQ API
plugin-6.7: Plugin code for SQ 6.7
plugin-7.6: Plugin code for SQ 7.6
dist: Builds a distribution zip containing the CLI utility, both plugin versions, dependency licenses and source code
Most of the source code and resources are the same for both plugin-6.7 and 7.6; only a small number of classes are different. As such I would like to move this common code to some shared source folder/module.
I would still like to compile this common code twice though, to verify the code compiles against both SQ API versions. In Eclipse this should show up as two separate source folders or projects, so I can easily verify that the common code doesn't use any SQ API's that are not yet available in 6.7 API, and doesn't use any API's that have been removed or deprecated in 7.6 API.
Preferably I would like to stick with building both plugin versions in a single build, so if possible I would like to avoid having to use two separate profiles.
Is this possible in any way?
What I have tried
With Maven I have found several ways for getting this to work, but I cannot get any of these approaches to work with m2eclipse.
Approach 1
Create a new module plugin-common, containing pom-6.7.xml and pom-7.6.xml. Both pom's are essentially the same apart from artifact id or classifier, and dependency on different SQ API version. Parent project defines these as 2 separate modules using
<module>plugin-common/pom-6.7.xml</module>
<module>plugin-common/pom-7.6.xml</module>
The issue with this approach is that I can't import these modules into Eclipse, as m2eclipse only supports pom.xml as the filename.
Approach 2
Similar to the above, but using separate sub-directories for the pom.xml files and using <sourceDirectory>${project.basedir}/../src/main/java</sourceDirectory> to point to the common source code:
plugin-common
src/main/java
src/main/resources
pom.xml: parent for 6.7 and 7.6 modules
6.7/pom.xml
7.6/pom.xml
This approach allows for importing both plugin-common versions into Eclipse, but Eclipse complains about 'Access .../src/main/java directory outside of project base directory'. As such it doesn't show any source code in the two plugin-common projects.
Approach 3
Don't have any pom.xml files in plugin-common, but instead add the common code as source folders to both plugin-6.7 and plugin-7.6 modules using build-helper-maven-plugin, using <source>${project.basedir}/../plugin-common/src/main/java</source>.
Again this fails in Eclipse due to the 'Access .../src/main/java directory outside of project base directory' warning.
I have now opted for the following approach, which works quite well.
Maven structure:
parent
common: Common code used by both tool and both plugin versions, doesn't use SQ API
tool: Some related command-line utility, doesn't use SQ API
plugin: SonarQube plugin code
dist: Builds a distribution zip containing the CLI utility, both plugin versions, dependency licenses and source code
The plugin module contains 3 base packages:
myproject.plugin.common: Code shared between SQ 6.7 and 7.6 implementations
myproject.plugin.sq67: Code specific for SonarQube 6.7 - 7.5.x
myproject.plugin.sq76: Code specific for SonarQube 7.6+
The plugin/pom.xml uses SonarQube API dependency and packaging plugin definitions similar to the following:
<dependency>
<groupId>org.sonarsource.sonarqube</groupId>
<artifactId>sonar-plugin-api</artifactId>
<version>${sonarqube.version}</version>
<scope>provided</scope>
</dependency>
<plugin>
<groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId>
<artifactId>sonar-packaging-maven-plugin</artifactId>
<version>1.16</version>
<extensions>true</extensions>
<configuration>
<pluginKey>mykey</pluginKey>
<pluginClass>myproject.plugin.common.MyPlugin</pluginClass>
<pluginName>PluginName</pluginName>
<pluginDescription>Description</pluginDescription>
<useChildFirstClassLoader>true</useChildFirstClassLoader>
<sonarQubeMinVersion>6.7</sonarQubeMinVersion>
</configuration>
</plugin>
This allows the plugin to work with SonarQube 6.7+, even if the API dependency version is set to 7.6 (see profiles below). The MyPlugin class is a generic class that uses Java reflection to load a 6.7-specific or 7.6-specific implementation depending on the SonarQube version that the plugin is running in.
Finally, the parent pom.xml defines the following two profiles:
<profiles>
<profile>
<id>default</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<sonarqube.version>7.6</sonarqube.version>
</properties>
<modules>
<module>common</module>
<module>plugin</module>
<module>tool</module>
<module>dist</module>
</modules>
</profile>
<profile>
<id>checkSQ6.7Compatibility</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<sonarqube.version>6.7</sonarqube.version>
</properties>
<modules>
<module>common</module>
<module>plugin</module>
</modules>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/sq76/**</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
The default profile now builds a plugin that is compatible with SonarQube 6.7 and up, with 7.6-specific features enabled if running on that version of SonarQube.
The checkSQ6.7Compatibility profile overrides the SonarQube API version to 6.7, excludes any SonarQube 7.6-specific folders, and only builds the common and plugin modules (skipping tool and dist). This allows for verifying that the common and 6.7-specific packages compile OK with the 6.7 API.
In Eclipse, I now use the default profile for regular development, allowing me to work on both 6.7 and 7.6 specific code at the same time. After any major changes, I can simply select the checkSQ6.7Compatibility profile in the Eclipse project configuration, in order to verify that I haven't accidentally introduced a dependency on any 7.6-specific API's.

maven install how to install and deploy *ONLY* ejb-client

I'm using the maven-ejb-plugin to generate ejb client for my client, in the standard way
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ejb-plugin</artifactId>
<version>2.3</version>
<configuration>
<ejbVersion>3.0</ejbVersion>
<generateClient>true</generateClient>
</configuration>
</plugin>
So the client use its dependecy
<dependency>
<groupId>en.foo.ejb</groupId>
<artifactId>artifact-ejb</artifactId>
<version>1.0.0</version>
<type>ejb-client</type>
</dependency>
I'm having 2 issues so far:
Launching mvn clean install or mvn clean deploy install ALSO the whole ejb package jar, so in the end I'll have both
artifact-ejb.jar
artifact-ejb-client.jar
I'd expect to install only the second one, because the artifact-ejb.jar should not be installed on the repository
The ejb artifact includes a parent pom, so when the client try to resolve all the dependencies it says the parent pom cannot be found on the repository, however the parent it is not meant to be distributed because it is only a reference.
(see also https://howtodoinjava.com/maven/maven-parent-child-pom-example/)
How can I solve these issues ?
Your artifact-ejb-client.jar contains only the interfaces. At runtime, you need to have the implementations as well. So if you want to build a proper ear or war, you need both artifact-ejb-client.jar and artifact-ejb.jar. The only exception that comes to my mind is RMI communication where you would be fine having only the client (on the calling side). So think about whether you really want to keep the artifact-ejb.jar out of your repository.
If you decide to do so, split your project into two separate projects, one containing the interfaces and one containing the implementations. The impl-project needs the client-project as dependency. Then you can freely build and deploy just one of the two.
For the parent poms: All parent poms of your artifacts need to be in the repository, otherwise the builds will break. If you depend on an artifact, you need to resolve its parent pom. It cannot be kept "secret".

Downloading artifacts with all classifiers into a chosen directory

We have a private repository at work so once a while we need to download artifacts from the central repository and upload them.
Someone wrote a program a while ago for that which didn't always work perfectly: it would download all dependencies for each artifact separately, it would first scan the dependency tree and only then download them, it wouldn't download sources and javadocs, was slow, etc.
Recently I have come across this useful maven plugin called dependency and its goal get.
So now to download some artifact, let's say for instance com.sparkjava.spark-core:2.5.4, I would type on my terminal:
mvn dependency:get -Dartifact=com.sparkjava:spark-core:2.5.4
mvn dependency:get -Dartifact=com.sparkjava:spark-core:2.5.4:sources
mvn dependency:get -Dartifact=com.sparkjava:spark-core:2.5.4:javadoc
Which would download the artifact along with all its dependencies to the directory ~/.m2/repository which I can later transfer to our private repository.
This method works good but has 2 problems:
I have to run the command 3 times when each time the classifier is different and I would like to get all classifiers at once.
It always downloads the artifacts into ~/.m2/repository, which can sometime contain other artifacts I'm not intrested in having on the private repository. I need be able to choose another directory destination.
What can I do about these issues? About the first one I can work it around with an alias (which will still run the same command 3 times) but I have no idea what to do about the second issue and it's not mentioned on the plugin's documentation either.
To solve (2), you can update the settings.xml with a tag
<localRepository>C:\Users\my\custom\existing\directory</localRepository>
and make sure when you are building the project, the same settings.xml looked into which can be done using
mvn clean install -gs <pathToDirectory>
Note - Please modify the path accordingly.
To solve (1), adding the following to settings.xml should work as well -
<profiles>
<profile>
<id>downloadSources</id>
<properties>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
</properties>
</profile>
</profiles>
<activeProfiles>
<activeProfile>downloadSources</activeProfile>
</activeProfiles>
Source - Maven – Always download sources and javadocs
Other maven command that could help here is -
resolve command with classifier :
mvn dependency:resolve -Dclassifier=javadoc #downloads all the documentation

Get started with maven

I have experience in Ant, how to get started with maven. Any advantage with maven over ant?
There's a quite large difference, where ant forces you to create your own targets you will get a default set of targets for maven, e.g., clean, install, package etc without scripting them.
Maven promotes that you use a common directory structure for java classes, resources etc. If you do, maven is just on xml file where you specify some project metadata such as name, package and most importantly depenencies. It provides similar dependency lookup to what ivy does for ant.
Based on the standard maven promotes, it becomes very easy for developers to approach and build your projects. With an IDE such as Netbeans it's enough to select open project, and then hit the install button to compile and install the project in your local repository.
I recommend working with maven the maven way. Doing things differently will often cause more pain than it's worth. Maven offers a plugin structure where you can perform various tasks, such as invoke the ant-library should you need to. If you're actively working with multiple projects (and want project switching to be as easy as possible) maven is a huge leap forward, especially if combined with repository server such as Nexus or Archiva.
To get started
Either you can generate your project structure using the archetype goal of maven, or you could do it the way I do by copy-pasing an empty template project every time. Then you need the maven binary and the project definition file pom.xml which I typically also copy paste between projects.
A sample is included below. With this sample you'll get the external library log4j, and you automatically get all nececcities to build and package your own project (in this case to a jar file).
<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>projectname</artifactId>
<packaging>jar</packaging>
<version>0.1.0-SNAPSHOT</version>
<name>${project.artifactId}</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<!-- add more dependencies here ... -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Around two weeks ago, I was in the same situation. In my opinion, Maven is a lot more powerful as compared to Ant.
It has a generate command which makes it very easy to start new projects of various kinds (artifacts) and will also build a standard directory structure along with the pom.xml file,
thereby taking care of a lot of things that are needed to be written in the build.xml file of Ant.
Managing dependencies is also a lot better. Maven will download dependencies from repos and will store them in a central repo on your system. If a dependency is already present in the local repository, it will take it from there instead of downloading it again.
I use eclipse and maven has a command (mvn eclipse:eclipse) which creates the .classpath file in the project directory. So no need to add the libraries again in eclipse.
The Getting started guide on the maven website is a good resource and covers quite a lot of stuff -
In comparison to Ant what Maven does well is dependency management and standardisation of the build lifecycle.
As for learning a bit more about it, the Maven documentation is pretty readable and thorough.
I'd start by looking at the introductory piece that explains some of the core principles about the difference between Maven and other build tools.
http://maven.apache.org/what-is-maven.html
Then downlod and install maven, open your terminal and type...
mvn archetype:generate
Select all defaults and you'll end up with a simple build-able project with one runnable class and a matching test file. Use that as a test project to familiarise yourself with the build lifecycle and dependency resolution process.

Using Hudson and Maven to release an application for multiple platforms

This question is not really about best practices or architecture, but about how to specifically configure Hudson and Maven to accomplish what I want. I'm a bit lost.
I have a Java application which uses SWT, and I need to build copies for different platforms. For now, all I need is Linux i386 and Linux amd64, but in the future, I need to add Windows x86/x64 as well, so I want to make sure I set it up "right" the first time around.
My application has all of the dependencies and other information listed in the Project pom.xml, including the different SWT jars to grab depending on OS, arch, and family.
My question is, how do I do builds for both linux i386 and linux amd64 with a minimal amount of configuration duplication? Right now I'm doing the following:
Project specifies all dependencies in pom.xml, and this project is set to build in Hudson and deploy the resulting .jar to Nexus
Builder-linux-i386 runs after Project and specifies any JNI files for i386 and uses the de.tarent maven-pkg-plugin to grab the project jar from Nexus and assemble it along with all dependencies into a single 'fat' jar file, and then into a .deb file for installation.
Builder-linux-amd64 does the same, but for amd64 files
I have been trying to specify which dependencies to use in the Builder projects by adding -P profilename to their Hudson projects, where profilename is a profile named in the Project pom. Maven doesn't seem to like this and prints that it is not activating that profile. It only uses the default profile from Project's pom.
What is the correct way to set this up? I want to have all of my dependencies specified in my Project pom, and have a Hudson project which compiles the jar for that project and deploy it to Nexus, and then independent projects which grab that jar and assemble it along with platform-specific files for release. I don't want to build the entire original project repeatedly, and I don't want to have a ton of duplicated configuration info or copy-pasted poms.
I have it working for unix-amd64 only because that's what the build machine is, so Maven targets that architecture. Also, I feel like the setup isn't as clean as it could be. Advice?
You have an syntax error. It needs to be -Pprofilename. It works for me this way.
Edit
Since the profile is read. There might be an syntax error in your profile configuration. I found a profile in one of projects, that I integrate into our CI environment. It defines some dependencies, it might help you.
<profile>
<id>junit</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>false</skip>
<testNGArtifactName>none:none</testNGArtifactName>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.4</version>
<scope>test</scope>
</dependency>
</dependencies>
</profile>
Profiles should work in the way you desciped it (you could post an other question about this).
But at (least for web applications) there is an other way: Try to use classifier instead of profiles to build for different environments. -- You can have a look at this blog: http://blog.jayway.com/2010/01/21/one-artifact-with-multiple-configurations-in-maven/
The purpuse of this solution is, that you are able to build (if you want (controlled by an profile)) for all environments at once.
The builder projects do not see the profiles from the main Project because it is not actually a parent. I cannot define it as a in the builder projects because my projects are not set up that way, and I'm building using variables like ${SVN_REVISION}, which maven does not like.
I have given up and instead copy-pasted the profiles into the 'builder' projects. This isn't the prettiest but for now it works.

Categories

Resources