Skip to content

Ant

Deploying to OSSRH with Apache Ant - Introduction⚓︎

Apache Ant can be configured to fulfill the requirements for component deployment to the Central Repository in various ways. In fact Apache Ant itself is released to the Central Repository.

Apache Ant provides tasks for creating the components required. The deployment itself can be performed with Apache Ivy or the Aether Ant tasks. Eclipse Aether is the repository access component used in Maven 3+. The old Maven Ant tasks can be used as well although they are using components of the deprecated Maven 2.

In the following examples we will assume a project directory setup of

build.xml
pom.xml
src/
lib/
...

where the src folder contains Java source code and the pom.xml fulfills the requirements. These locations are stored in properties in the build.xml file

<property name="src" location="src" />
<property name="build" location="build" />
<property name="dist" location="dist" />

A build and a dist and nested lib folder are created in the init task.

<target name="init">
  <mkdir dir="${build}" />
  <mkdir dir="${dist}/lib" />
</target>

and components coordinated and names are declared using Maven repository naming conventions

<!-- define Maven coordinates -->
<property name="groupId" value="com.juvenxu" />
<property name="artifactId" value="ant-demo" />
<property name="version" value="1.0-SNAPSHOT" />
<!-- define artifacts' name, which follows the convention of Maven -->
<property name="jar" value="${dist}/lib/${artifactId}-${version}.jar" />
<property name="javadoc-jar" value="${dist}/lib/${artifactId}-${version}-javadoc.jar" />
<property name="sources-jar" value="${dist}/lib/${artifactId}-${version}-sources.jar" />

The credentials for accessing OSSRH are stored in the Maven settings.xml for usage by the Aether or Maven Ant tasks for simplicity. For Ivy usage a property file will be used.

Compilation and Jar Creation⚓︎

In our example we are compiling and creating the jar file with the following commands.

<target name="compile" depends="init">
  <javac srcdir="${src}" destdir="${build}" />
</target>

<target name="jar" depends="compile">
  <!-- build the main artifact -->
  <jar jarfile="${jar}" basedir="${build}" />
</target>

The main output of this task is the jar file we are going to deploy using the name defined in the jar property locating the file in the dist/lib folder, where the deploy tasks will pick them up from.

Javadoc and Sources Jar Creation⚓︎

The JavaDoc and Sources jar creation is accomplished with the following defintion.

<target name="dist" depends="jar">
  <!-- build the javadoc jar -->
  <javadoc sourcepath="${src}" destdir="${dist}/javadoc" />
  <jar jarfile="${javadoc-jar}">
    <fileset dir="${dist}/javadoc" />
  </jar>

  <!-- build the sources jar -->
  <jar jarfile="${sources-jar}">
    <fileset dir="${src}" />
  </jar>
</target>

Again the main result is the properly named jar files found in the dist/lib folder.

Signing and Deployments Using the Maven Ant Tasks⚓︎

The Maven Ant tasks can be used to execute the Maven deploy plugin.

With the setup above and the Maven Ant tasks available on the classpath of your Ant execution, you can define a stage target to publish to OSSRH.

Note: As of February 2021, all new projects began being provisioned on https://s01.oss.sonatype.org/. If your project is not provisioned on https://s01.oss.sonatype.org/, you will want to reference the legacy host https://oss.sonatype.org/.

<project name="ant-demo" default="deploy" basedir="." xmlns:artifact="antlib:org.apache.maven.artifact.ant">

  <!-- defined maven snapshots and staging repository id and url -->
  <property name="ossrh-snapshots-repository-url"
    value="https://s01.oss.sonatype.org/content/repositories/snapshots/" />
  <property name="ossrh-staging-repository-url"
    value="https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/" />
  <!-- there server id in the Maven settings.xml -->
  <property name="ossrh-server-id" value="ossrh" />

  <target name="deploy" depends="dist" description="deploy snapshot version to Maven snapshot repository">
    <artifact:mvn>
      <arg value="org.apache.maven.plugins:maven-deploy-plugin:2.6:deploy-file" />
      <arg value="-Durl=${ossrh-snapshots-repository-url}" />
      <arg value="-DrepositoryId=${ossrh-server-id}" />
      <arg value="-DpomFile=pom.xml" />
      <arg value="-Dfile=${jar}" />
    </artifact:mvn>
  </target>

  <!-- before this, update project version (both build.xml and pom.xml) from SNAPSHOT to RELEASE -->
  <target name="stage" depends="dist" description="deploy release version to Maven staging repository">
    <!-- sign and deploy the main artifact -->
    <artifact:mvn>
      <arg value="org.apache.maven.plugins:maven-gpg-plugin:1.3:sign-and-deploy-file" />
      <arg value="-Durl=${ossrh-staging-repository-url}" />
      <arg value="-DrepositoryId=${ossrh-server-id}" />
      <arg value="-DpomFile=pom.xml" />
      <arg value="-Dfile=${jar}" />
      <arg value="-Pgpg" />
    </artifact:mvn>

    <!-- sign and deploy the sources artifact -->
    <artifact:mvn>
      <arg value="org.apache.maven.plugins:maven-gpg-plugin:1.3:sign-and-deploy-file" />
      <arg value="-Durl=${ossrh-staging-repository-url}" />
      <arg value="-DrepositoryId=${ossrh-server-id}" />
      <arg value="-DpomFile=pom.xml" />
      <arg value="-Dfile=${sources-jar}" />
      <arg value="-Dclassifier=sources" />
      <arg value="-Pgpg" />
    </artifact:mvn>

    <!-- sign and deploy the javadoc artifact -->
    <artifact:mvn>
      <arg value="org.apache.maven.plugins:maven-gpg-plugin:1.3:sign-and-deploy-file" />
      <arg value="-Durl=${ossrh-staging-repository-url}" />
      <arg value="-DrepositoryId=${ossrh-server-id}" />
      <arg value="-DpomFile=pom.xml" />
      <arg value="-Dfile=${javadoc-jar}" />
      <arg value="-Dclassifier=javadoc" />
      <arg value="-Pgpg" />
    </artifact:mvn>
  </target>

  <target name="clean" description="clean up">
    <delete dir="${build}" />
    <delete dir="${dist}" />
  </target>
</project>

You'll notice that the stage target above calls artifact:mvn three times, each time with an argument of -Pgpg. This assumes that you have created a profile called gpg in your .m2/settings.xml file. Using this profile, you can specify the passphrase to unlock your private key. See below for an example settings.xml:

<settings>
  <servers>
    <server>
      <id>ossrh</id>
      <username>token-username</username>
      <password>token-password</password>
    </server>
  </servers>
  <profiles>
    <profile>
      <id>gpg</id>
      <properties>
        <! -- Optionally specify a different path and name for the gpg executable
              if it differs from the default of "gpg"           
        <gpg.executable>gpg2</gpg.executable>
        -->
        <gpg.passphrase>xxxxxx</gpg.passphrase>
      </properties>
    </profile>
  </profiles>
</settings>

Do not use your login username and password in settings.xml

Please do not use your UI login username and password in settings.xml. Use the token that was previously generated.

Note also how the id element in the server block above matches the value of the ossrh-server-id variable used in build.xml. This is how the ant tasks will look up your credentials when deploying to OSSRH.

Signing Components⚓︎

If you decide to use Ant directly to sign your components you can use the signer Ant task.

Deployments Using Apache Ivy⚓︎

Apache Ivy allows resolving as well a publishing components to a repository. The signed components can be deployed to OSSRH with the publish task.

Deployments Using the Aether Ant Tasks⚓︎

The Aether Ant tasks are using the same component to interact with Maven repositories as Apache Maven - Eclipse Aether. You can publish your signed components with the deploy task.

Examples⚓︎