[Legacy OSSRH] Open-source your Java Library by publishing to Maven Central using GitHub Actions

[Legacy OSSRH] Open-source your Java Library by publishing to Maven Central using GitHub Actions

This article is outdated, Sonatype migrated away from the legacy method of publishing via OSSRH. https://central.sonatype.org/register/central-portal/#create-an-account

I have written an updated tutorial on how to deploy your Java library to Maven Central. https://www.dhirubhai.net/pulse/publishing-your-java-library-maven-central-using-yi-leng-yao-183zf/

If you have an awesome Java library that you want to leverage as a dependency in other projects, share with your team, friends or the broader developer community. Consider open-source the library by publishing it to Maven Central via GitHub Actions, so the artifact will be publicly accessible and usable by other developers around the world.

Premise

You have a Java library on hosted on GitHub, and you would like to host the artifact generated from this library on a open source hosting service, allowing other Java projects to import your library as a dependency.

Requirements

  • Java (17 in this example)
  • Maven

(Optional) Create and Host your Maven repository

You can skip this step if you already have a Java library hosted on GitHub.

Maven is a build automation and dependency management tool for Java projects. We will be using maven to bootstrap our Java library, compile the library into an artifact and publish to Maven Central.

To bootstrap your Java library.

mvn archetype:generate -DgroupId=<group-id> -DartifactId=<project name> -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false        

you need to provide the group id and project name.

Create a GitHub repository and add your Java library to the repository.

Create your OSSRH Account and Project

OSSRH stands for "Open Source Software Repository Hosting." It refers to the Nexus Repository Manager provided by Sonatype, which serves as an open-source platform to host you Java library. We will use OSSRH interchangebly with Maven Central and Staging.

Maven Central: is the primary repository of artifacts for the Java community. It’s where most Java developers pull their dependencies from.

Maven Staging: is the temporary hosting area of your artifact for testing purposes before promoting your artifact to Maven Central.

If you do not have an OSSRH Account or Project let’s create one.

  1. Create you JIRA account
  2. Create a New Project ticket

  • Group Id: Register a domain that you own, if you don’t have one you can use the format io.github.<github username>
  • Project URL: If you do not have a project website, you can use the URL of your GitHub repository.
  • SCM url: You can get your SCM url in your GitHub repository press code.

Creating your repository usually takes less than 2 business, I would like to give a shoutout to Joel Orlina from Sonatype for their swift response in setting up the OSSRH repo.

You can read more about setting up your OSSRH project here.

Maven Plugin Setup

Add the following in your pom.xml

Licensing

  <licenses>
    <license>
      <name>MIT License</name>
      <url>https://www.opensource.org/licenses/mit-license.php</url>
    </license>
  </licenses>        

Developer Information

  <developers>
    <developer>
      <name>Your name</name>
      <organization>Organization name</organization>
      <organizationUrl>Organization url</organizationUrl>
    </developer>
  </developers>        

Make sure to replace placeholders like Your name, Organization name, and Organization url , with your actual details.

SCM Information

  <scm>
    <connection>scm:git:git://github.com/{username}/{git repository name}.git</connection>
    <developerConnection>scm:git:ssh://github.com:{username}/{git repository name}.git</developerConnection>
    <url>https://github.com/{username}/{git repository}/tree/main</url>
  </scm>        

Make sure to replace placeholders like username and git repository name , with your actual details.

Distribution Management

  <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>        

Javadoc and Sources Plugin

      <!-- Plugin for Javadoc and Sources -->
      <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>3.3.0</version>
        <configuration>
          <links>
            <link>https://docs.oracle.com/en/java/javase/17/docs/api/</link>
          </links>
        </configuration>
        <executions>
          <execution>
            <id>attach-javadocs</id>
            <goals>
              <goal>jar</goal>
            </goals>
          </execution>
        </executions>
      </plugin>        

Nexus Staging Plugin

      <plugin>
        <groupId>org.sonatype.plugins</groupId>
        <artifactId>nexus-staging-maven-plugin</artifactId>
        <version>1.6.13</version>
        <extensions>true</extensions>
        <configuration>
          <serverId>ossrh</serverId>
          <nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
          <autoReleaseAfterClose>${env.AUTO_RELEASE_AFTER_CLOSE}</autoReleaseAfterClose>
        </configuration>
      </plugin>        

This will deploy the build artifacts of your Java library to to the Sonatype Nexus repository.

The <autoReleaseAfterClose> configuration

  • When set to false : Your artifact is only published to the Nexus staging repository, allowing for manual verification and release.
  • When set to true : The artifact is initially published to the staging repository and automatically promoted to Maven Central for public access.

GPG Plugin for Artifact Signing

      <!-- GPG Signed Components -->
      <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>
            <configuration>
              <gpgArguments>
                <arg>--pinentry-mode</arg>
                <arg>loopback</arg>
              </gpgArguments>
              <passphrase>${env.GPG_PASSPHRASE}</passphrase>
            </configuration>
          </execution>
        </executions>
      </plugin>        

Signing build artifacts with GPG is a requirement for publishing to Maven Central for security and authenticity.

Here the <passphrase>${env.GPG_PASSPHARASE}</passphrase> is passed in as an environment variable when the GitHub action is executed. The specifics of setting this environment variable will be explored in the upcoming section when we configure the GitHub Action.

Maven Settings for OSSRH Deployment

To set up Maven for OSSRH deployment, incorporate the provided settings.xml into your repository:

<?xml version="1.0" encoding="UTF-8"?>
<settings xsi:schemaLocation="https://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd"
          xmlns="https://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
    <servers>
        <server>
            <id>ossrh</id>
            <username>${env.MAVEN_USERNAME}</username>
            <password>${env.MAVEN_PASSWORD}</password>
        </server>
    </servers>
</settings>        

This configuration allows maven to fetch the MAVEN_USERNAME and MAVEN_PASSWORD from the GitHub action environment variables, granting the action the necessary permissions to deploy to the Maven staging repository.

Publish your Library with GitHub Actions

  1. Create the folder .github/workfows/ in your repository
  2. Add the maven-publish.yml configuration file with the content

name: Publish Package to Maven Central

on:
  pull_request:
    branches:
      - main
      - develop
    types: [closed]

jobs:
  publish:
    if: github.event.pull_request.merged == true
    runs-on: ubuntu-latest
    steps:
      - name: Step 1 - Checkout code
        uses: actions/checkout@v3

      - name: Step 2 - Import GPG key
        run: |
          echo "${{ secrets.GPG_PUBLIC_KEY }}" | gpg --import
          echo "${{ secrets.GPG_SECRET_KEY }}" | gpg --import --no-tty --batch --yes

      - name: Step 3 - Set up Maven Central Repository
        uses: actions/setup-java@v3
        with:
          java-version: "17"
          distribution: "temurin"
          server-id: ossrh
          server-username: MAVEN_USERNAME
          server-password: MAVEN_PASSWORD

      # Set AUTO_RELEASE_AFTER_CLOSE based on branch and adjust version if develop
      - name: Step 4 - Prepare Environment Variables and Adjust Version if Develop Branch
        run: |
          if [[ "${{ github.base_ref }}" == "main" ]]; then
            echo "AUTO_RELEASE_AFTER_CLOSE=true" >> $GITHUB_ENV
          else
            echo "AUTO_RELEASE_AFTER_CLOSE=false" >> $GITHUB_ENV
            # Extract current version, append -SNAPSHOT and update the pom.xml
            VERSION=$(mvn -q -Dexec.executable=echo -Dexec.args='${project.version}' --non-recursive exec:exec)
            NEW_VERSION="${VERSION}.$(date +'%Y%m%d%H%M%S')-SNAPSHOT"
            mvn versions:set -DnewVersion=$NEW_VERSION
          fi

      - name: Step 5 - Publish package
        run: mvn --batch-mode deploy
        env:
          MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
          MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
          GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}        

The provided configuration initiates a GitHub Action when a PR merges into either the main or develop branch (create a develop branch in your GitHub repository is you have not).

if [[ "${{ github.base_ref }}" == "main" ]]; then
            echo "AUTO_RELEASE_AFTER_CLOSE=true" >> $GITHUB_ENV
          else
            echo "AUTO_RELEASE_AFTER_CLOSE=false" >> $GITHUB_ENV
            # Extract current version, append -SNAPSHOT and update the pom.xml
            VERSION=$(mvn -q -Dexec.executable=echo -Dexec.args='${project.version}' --non-recursive exec:exec)
            NEW_VERSION="${VERSION}.$(date +'%Y%m%d%H%M%S')-SNAPSHOT"
            mvn versions:set -DnewVersion=$NEW_VERSION
          fi        

The above configuration will set the configuration <autoReleaseAfterClose> to true when you merge to main and false if your merge to develop.

So merging your PR to

  • The develop branch: Your artifact is only published to the Maven staging repository, allowing for manual verification and release.
  • The main branch: The artifact is initially published to the staging repository and automatically promoted to Maven Central for public access.

This strategy allows to do testing and verification on Maven staging by merging your PR to the develop branch. Once testing is done, merging a PR to the main branch will make your library public by publishing to Maven Central.

Since you cannot overwrite an artifact version on Maven staging or Central, this code NEW_VERSION”${VERSION}.$(date+'%Y%m%d%H%M%S')-SNAPSHOT” will append timestamp and “SNAPSHOT” to a version number. This guarantees a distinct version each time you deploy to Maven staging for testing.

The following secret keys are needed to publish to OSSRH (Maven Central or Staging)

  • secrets.OSSRH_USERNAME
  • secrets.OSSRH_TOKEN
  • secrets.GPG_PUBLIC_KEY
  • secrets.GPG_SECRET_KEY
  • secrets.GPG_PASSPHRASE

Setting up Secret Keys

Accessing OSSRH Credentials

Log into https://s01.oss.sonatype.org/ , then go to Profile, and click on Access User Token

After clicking on “Access User Token”, you’ll see two pieces of information:

  • username will serve as your OSSRH_USERNAME.
  • password will be your OSSRH_TOKEN.

GPG Key Generation

GPG keys are essential for signing your artifact before publishing to OSSRH, ensuring its authenticity and integrity.

Download and install GPG from https://gnupg.org/download/index.html#sec-1-2 .

Run the following command to generate your GPG keys, remember to use the email associated with your OSSRH account, and remember your passphrase.

gpg --gen-key        

Then run the following commands to export GPG_PUBLIC_KEY and GPG_SECRET_KEY.

gpg --armor --export YOUR_EMAIL_USED_WHEN_GENERATING_THE_KEY > public-key.gpg
gpg --armor --export-secret-key YOUR_EMAIL_USED_WHEN_GENERATING_THE_KEY > secret-key.gpg        

Setting Up Github Secrets

On your GitHub repository go to Settings then Secrets and variables , then click Actions

Then click on New repository secret

Then fill the the secret for the secret keys, and click on add secrets

  • OSSRH_USERNAME
  • OSSRH_TOKEN
  • GPG_PUBLIC_KEY
  • GPG_SECRET_KEY
  • GPG_PASSPHRASE

Deployment Workflow

Now we are ready to deploy your package.

Deploy to Staging

Open a PR that merges to the develop branch.

After merging the PR, a GitHub Action is initiated to deploy to Maven Staging. The artifact’s URL can be located within the logs of this GitHub Action.

You can also find your published artifact on Maven staging by going to https://s01.oss.sonatype.org/ and searching for your groupid.

To pull artifacts from Maven staging into another Java repository, modify the pom.xml of that repository. First, add the Maven staging repository:

<repositories>
    <!-- other repositories if any -->
    <repository>
        <id>ossrh-staging</id>
        <url>https://s01.oss.sonatype.org/content/repositories/staging/</url>
        <releases>
            <enabled>false</enabled>
        </releases>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </repository>
</repositories>        

Then, include your artifact as a dependency:

<dependencies>
    <!-- other dependencies if any -->
    <dependency>
        <groupId>your.group.id</groupId>
        <artifactId>your-artifact-id</artifactId>
        <version>your-version</version>
    </dependency>
</dependencies>        

Deploy to Maven Central

After thoroughly testing your code, open a PR targeting the main branch. Once merged, this will activate a GitHub Action to deploy to Maven Central.

Upon successful completion of the GitHub action, you can locate your artifact on Maven staging at https://s01.oss.sonatype.org/. Typically, within 10 minutes, your artifact will be available on Maven Central. Simply visit https://central.sonatype.com/ or https://mvnrepository.com/ and a search with yourgroupId.

Congratulations! Your library is now accessible to the global developer community.

Here is the related GitHub repo for reference:

Happy Developing! ??.

Related Medium article


Parvez Hassan

Technical Architect Backend @ OLX | Standup Comedian

8 个月

How do i get OSSRH Credentials? for https://s01.oss.sonatype.org/?

回复

要查看或添加评论,请登录

Yi leng Yao的更多文章

社区洞察

其他会员也浏览了