Maven Central

Maven Central, located at https://central.sonatype.com/, is a repository that is used to store Java libraries. It is the default repository for Maven and Gradle builds and therefore publishing libraries to Maven Central is a common practice for Java developers making them easily available to other developers.

UnitVectorY Labs publishes various Java libraries under the component namespace com.unitvectory.

Publishing to Maven Central

Publish to Maven Central requires several steps to be completed on Sonatype’s website, which are best described in their Getting Started guide.

The rest of this document will focus on the specific setup used by UnitVectorY labs.

Credit is due to the Over Engineering Blog that has a post which walks through the process of publishing to Maven Central with a GitHub action.

The GitHub action used to publish to Maven Central requires the following secrets to be added to the GitHub repository: OSSRH_USERNAME and OSSRH_TOKEN which are generated from Sonatype and will be used by the GitHub Action.

Maven Plugins for Publishing

Maven Central has several requirements for publishing libraries. This includes signing the library with a GPG key, providing a POM file, and providing a source and javadoc jar file. These requirements are met by including various plugins in the POM file.

The first is the GPG plugin that is used to sign the library.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-gpg-plugin</artifactId>
    <version>3.2.4</version>
    <executions>
        <execution>
            <id>sign-artifacts</id>
            <phase>verify</phase>
            <goals>
                <goal>sign</goal>
            </goals>
            <configuration>
                <gpgArguments>
                    <arg>--pinentry-mode</arg>
                    <arg>loopback</arg>
                </gpgArguments>
            </configuration>
        </execution>
    </executions>
</plugin>

The next plugin is the Javadoc plugin that is required to create the Javadoc jar file.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-javadoc-plugin</artifactId>
    <version>3.6.3</version>
    <executions>
        <execution>
            <id>attach-javadoc</id>
            <goals>
                <goal>jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>

A related plugin is the Source plugin that is required to create the source jar file.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-source-plugin</artifactId>
    <version>3.3.1</version>
    <executions>
        <execution>
            <id>attach-source</id>
            <goals>
                <goal>jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>

The last required plugin is the plugin that is used to publish the library to Maven Central.

<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>
        <autoPublish>true</autoPublish>
    </configuration>
</plugin>

That is it for the required plugins. This is enough that the mvn deploy command can be used to publish the library to Maven Central. However, it is recommended approach is to utilize a GitHub Action to perform this deployment.

GPG Signing Key

Maven Central requires a GPG signing key to be used to sign the library.

A GPG key must be generated and published to a key server. This guide will not go into the details of generating a GPG key.

Since the goal is to use GitHub Actions to sign and deploy the library, the GPG key must be added to the GitHub repository as a secret. The GPG key should be added as a secret named OSSRH_GPG_SECRET_KEY and the passphrase for the GPG key should be added as a secret named OSSRH_GPG_SECRET_KEY_PASSWORD.

Deploying with GitHub Actions

This requires setting up a GitHub Action that will build the library and then deploy it to Maven Central.

A working example can be found at https://github.com/UnitVectorY-Labs/fileparamunit/blob/main/.github/workflows/release.yml

name: Publish Java version to Maven Central
on:
  release:
    types: [published]
jobs:
  publish:
    runs-on: ubuntu-latest
    timeout-minutes: 30

    permissions:
      contents: write
      id-token: write
      attestations: write

    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Set up Java for publishing to Maven Central Repository
        uses: actions/setup-java@v4
        with:
          java-version: 17
          distribution: corretto
          server-id: central
          server-username: MAVEN_USERNAME
          server-password: MAVEN_PASSWORD
          gpg-private-key: $
          gpg-passphrase: MAVEN_GPG_PASSPHRASE

      - name: Extract Maven Artifacts
        id: maven_artifact
        run: |
          echo "version=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)" >> $GITHUB_OUTPUT
          echo "artifactId=$(mvn help:evaluate -Dexpression=project.artifactId -q -DforceStdout)" >> $GITHUB_OUTPUT

      - name: Build Java Project
        run: mvn clean package -ntp

      - name: Publish to the Maven Central Repository
        run: mvn deploy -ntp
        env:
          MAVEN_USERNAME: $
          MAVEN_PASSWORD: $
          MAVEN_GPG_PASSPHRASE: $

      - name: Publish Java Artifacts to GitHub Release
        run: |
          cp pom.xml $-$.pom
          gh release upload $ "$-$.pom"
          for jar in target/*.jar; do
            [ -e "$jar" ] || continue
            gh release upload $ "$jar"
          done
        env:
          GITHUB_TOKEN: $

      - name: GitHub Attestation for JAR files
        uses: actions/attest-build-provenance@v1
        with:
          subject-path: "target/*.jar"

      - name: GitHub Attestation for POM file
        uses: actions/attest-build-provenance@v1
        with:
          subject-path: "pom.xml"
          subject-name: "$-$.pom"

This GitHub action is triggered when a release is published. It sets up the Java environment, builds the library, and then deploys it to Maven Central with the appropriate signatures.

Additionally the JAR and POM artifacts are uploaded to the GitHub Release for reference.

The JAR and POM file aalso use a GitHub Attestation to provide proof of their provenance. This is not yet uploaded to Maven Central and is only available through GitHub to verify the artifact.