Update: This article now reference the new way for publishing, via Central Portal
JeKa is a modern Java build tool focused on simplicity.
This post demonstrates how to publish to Maven Central with minimal configuration.
Prerequisite: You need a Central Portal Accountto publish on Maven Central.
Configure and Run
With JeKa, you can fully configure the build by editing the jeka.properties file as follows:
jeka.version=0.11.37
jeka.java.version=17
jeka.classpath=dev.jeka:centralprotal-plugin
@project.moduleId=com.github.djeang:vincer-dom
@project.gitVersioning.enable=true
# Metadata required by Maven Central for publishing
@maven.pub.metadata.projectName=Vincer-Dom
@maven.pub.metadata.projectDescription=Modern Dom manipulation library for Java
@maven.pub.metadata.projectUrl=https://github.com/djeang/vincer-dom
@maven.pub.metadata.projectScmUrl=https://github.com/djeang/vincer-dom.git
@maven.pub.metadata.licenses=Apache License V2.0:https://www.apache.org/licenses/LICENSE-2.0.html
@maven.publication.metadata.developers=djeang:djeangdev@yahoo.fr
Note that dependencies are listed in a dedicated dependencies.txt file to maintain clear separation of concerns.
[version]
org.junit:junit-bom:5.12.2@pom
[compile]
[test]
org.junit.platform:junit-platform-launcher
org.junit.jupiter:junit-jupiter
org.jdom:jdom2:2.0.6.1
To publish to Maven Central, execute:
jeka project: pack centralportal: publish
See a concrete example here.
GitHub action
The following Github Action workflow builds the project and publish to Maven Central:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: git fetch --prune --unshallow --tags
- name: Build and publish
env:
JEKA_CENTRAL_PORTAL_USERNAME: ${{ secrets.CENTRAL_PORTAL_USERNAME }}
JEKA_CENTRAL_PORTAL_PASSWORD: ${{ secrets.CENTRAL_PORTAL_PASSWORD }}
JEKA_CENTRAL_PORTAL_SIGN_KEY: ${{ secrets.GPG_SECRET_KEY}}
JEKA_CENTRAL_PORTAL_SIGN_KEY_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
run: "./jeka build centralportal: publish"
Thanks to its powerful wrapper, Jeka will install specified JDK and Jeka version by itself.
Explanations
Now that you know how to do it, let's explain how it works.
Jeka and Java Versioning
For better portability and reproducibility, we can declare both the Jeka and Java versions required for building. Both versions will be automatically downloaded if not already present on the host machine.
Specify Module ID and Versioning
The published moduleId
is specified using the @project.moduleId
property.
The version can be explicitly specified using the @project.version
property. Note that properties can be set in the jeka.properties file or passed as a command-line argument: -D@project.version=1.0.1
.
Instead, we choose to rely on Git to infer the version using: @project.gitVersioning.enable=true
. If there is no tag on the current commit, the version will be set to [branch]-SNAPSHOT; otherwise, it will be the tag-name.
Provide secrets
To publish on Maven Central, we need to signs artefact files with the appropriate GPG key mentioned in Central Portal.
We also need to specify credentials at publication time.
For those, Jeka expects these values to be found in the followinng environment variables:
-
JEKA_CENTRAL_PORTAL_USERNAME
: OSSRH account username -
JEKA_CENTRAL_PORTAL_PASSWORD
: OSSRH account password -
JEKA_CENTRAL_PORTAL_SIGN_KEY
: Armored GPG secret key as a string -
JEKA_CENTRAL_PORTAL_SIGN_KEY_PASSPHRASE
: The passphrase protecting the secret key
The content of JEKA_CENTRAL_PORTAL_SIGN_KEY
can be obtained by executing: gpg --export-secret-key --armor MY-KEY
.
Provide Publication Metadata
The mandatory metadata are set using @maven.pub.metadata.xxx
properties.
Note that the @maven.pub.metadata.licenses
property expects a format like: [license1 name]:[license1 url],[license2 name]:[license2 url],...
Automate Release Publication
By default, the published artefacts are automatically published to Maven Central. If you want to just validate your publication an publish to Maven Central manually (from Central Portal UI), you need to specify this configuration:
@centralportal.automatic=false
Execute Build
To publish, simply execute: jeka project: pack centralportal: publish
.
This will:
- Create the JAR to publish (
project: pack
). - Create source and Javadoc JARs.
- Generate the published POM file.
- Compute all checksums.
- Sign all published files.
- Push everything to the Central Portal.
To see what will be published, execute: jeka maven: info
.
Find more details here.
Comparison with Maven
The following is the Maven POM configuration equivalent for deploying a project to Maven Central:
<?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>
<developers>
<developer>
<name>djeang</name>
<email>djeangdev@yahoo.fr</email>
</developer>
</developers>
<name>Vincer-DOM</name>
<description>Modern Dom manipulation library for Java.</description>
<url>https://github.com/djeang/vincer-dom</url>
<groupId>com.github.djeang</groupId>
<artifactId>vincer-dom</artifactId>
<version>0.1.0-SNAPSHOT</version>
<licenses>
<license>
<name>MIT License</name>
<url>http://www.opensource.org/licenses/mit-license.php</url>
</license>
</licenses>
<properties>
<java.version>17</java.version>
<maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version>
</properties>
<scm>
<connection>scm:git:git://github.com/djeang/vincer-dom.git</connection>
<developerConnection>scm:git:https://github.com/djeang/vincer-dom.git</developerConnection>
<url>https://github.com/djeang/vincer-domr</url>
</scm>
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.9.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<version>org.junit.jupiter</version>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<version>org.junit.platform</version>
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<version>org.jdom</version>
<artifactId>jdom2</artifactId>
<version>2.0.6.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.4.0</version>
<extensions>true</extensions>
<configuration>
<publishingServerId>central</publishingServerId>
<tokenAuth>true</tokenAuth>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>me.ccampo</groupId>
<artifactId>git-version-maven-plugin</artifactId>
<version>0.1.0</version>
<extensions>true</extensions>
<configuration>
<strategy hint="git"/>
</configuration>
</plugin>
</plugins>
</build>
</project>
Conclusion
Jeka provides a simpler, yet powerful way to build Java software and publish artifacts to Maven Central or other repositories, with much less configuration and effort than traditional tools.
Visit the website, videos, and examples to get an idea of everything Jeka can do better.
Disclaimer: I am the author of Jeka.