Publishing Java Projects
This page will discuss common topics around publishing your Java projects for others to use
Publishing Locally
package build
import mill._, javalib._, publish._
object foo extends JavaModule with PublishModule {
def publishVersion = "0.0.1"
def pomSettings = PomSettings(
description = "Hello",
organization = "com.lihaoyi",
url = "https://github.com/lihaoyi/example",
licenses = Seq(License.MIT),
versionControl = VersionControl.github("lihaoyi", "example"),
developers = Seq(Developer("lihaoyi", "Li Haoyi", "https://github.com/lihaoyi"))
)
}
This is an example JavaModule
with added publishing capabilities via
PublishModule
. This requires that you define an additional
publishVersion
and pomSettings
with the relevant metadata, and provides
the .publishLocal
and publishSigned
tasks for publishing locally to the
machine or to the central maven repository
> mill foo.publishLocal
Publishing Artifact(com.lihaoyi,foo,0.0.1) to ivy repo...
Checking API compatibility
Mill provides the ability to check API changes with the Revapi analysis and change tracking tool.
package build
import mill._, javalib._, publish._, revapi._
object bar extends JavaModule with RevapiModule {
def publishVersion = "0.0.1"
def pomSettings = PomSettings(
description = "Hello",
organization = "com.lihaoyi",
url = "https://github.com/lihaoyi/example",
licenses = Seq(License.MIT),
versionControl = VersionControl.github("lihaoyi", "example"),
developers = Seq(Developer("lihaoyi", "Li Haoyi", "https://github.com/lihaoyi"))
)
override def revapiConfigFiles: T[Seq[PathRef]] =
// add Revapi config JSON file(s)
Task.Sources(millSourcePath / "conf/revapi.json")
override def revapiClasspath: T[Agg[PathRef]] = T {
// add folder containing logback.xml
super.revapiClasspath() ++ Seq(PathRef(millSourcePath / "conf"))
}
}
This example uses the revapi
task, provided by the RevapiModule
, to run an
analysis on old and new archives of a module to identify incompatibilities.
For demonstration purposes, an archive, to compare against, is published locally. In real usage, the old version would be downloaded from the publish repository. |
> mill bar.publishLocal
Publishing Artifact(com.lihaoyi,bar,0.0.1) to ivy repo...
> cp dev/src/Visibility.java bar/src/Visibility.java
> mill bar.revapi
Starting analysis
Analysis results
----------------
old: field Visibility.SuperClass.f @ Visibility.SubClass
new: <none>
java.field.removed: Field removed from class.
... BREAKING
old: field Visibility.f
new: field Visibility.f
java.field.visibilityReduced: Visibility was reduced from 'public' to 'protected'.
... BREAKING
Analysis took ...ms.
The revapi task does not fail if incompatibilities are reported. You should fix these, and verify by re-running revapi , before a release.
|
The
|
Publishing to Sonatype Maven Central
Once you’ve mixed in PublishModule
, apart from publishing locally, you can also publish
your project’s modules to maven central
GPG
If you’ve never created a keypair before that can be used to sign your artifacts you’ll need to do this. Sonatype’s GPG Documentation has the instructions on how to do this
Publishing Secrets
Mill uses the following environment variables as a way to pass the necessary secrets for publishing:
# The LHS and RHS of the User Token, accessible through the sonatype
# website `Profile` / `User Token` / `Access User Token`
export MILL_SONATYPE_USERNAME=...
export MILL_SONATYPE_PASSWORD=...
# The base-64 encoded PGP key, which can be encoded in the following way
# for each OS:
#
# MacOS or FreeBSD
# gpg --export-secret-key -a $LONG_ID | base64
#
# Ubuntu (assuming GNU base64)
# gpg --export-secret-key -a $LONG_ID | base64 -w0
#
# Arch
# gpg --export-secret-key -a $LONG_ID | base64 | sed -z 's;\n;;g'
#
# Windows
# gpg --export-secret-key -a %LONG_ID% | openssl base64
export MILL_PGP_SECRET_BASE64=...
# The passphrase associated with your PGP key
export MILL_PGP_PASSPHRASE=...
Publishing
You can publish all eligible modules in your Mill project using
the default task of the
External Module mill.scalalib.PublishModule
:
mill mill.scalalib.PublishModule/
You can also specify individual modules you want to publish via a selector:
mill mill.scalalib.PublishModule/ foo.publishArtifacts
The default URL for publishing to sonatype’s Maven Central is oss.sonatype.org
.
Newer projects registered on sonatype may need to publish using s01.oss.sonatype.org
.
In that case, you can pass in a --sonatypeUri
:
mill mill.scalalib.PublishModule/ \
--sonatypeUri https://s01.oss.sonatype.org/service/local
This also allows you to publish to your own internal corporate sonatype deployment,
by passing in --sonatypeUri example.company.com
instead.
Since Feb. 2021 any new Sonatype accounts have been created on
The symptom of using the "wrong" URL for publishing is typically a 403 error code, in response to the publish request. Typically
|
Publishing Using Github Actions
To publish on Github Actions, you can use something like this:
# .github/workflows/publish-artifacts.yml
name: Publish Artifacts
on:
push:
tags:
- '**'
workflow_dispatch:
jobs:
publish-artifacts:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
- run: ./mill mill.scalalib.PublishModule/
env:
MILL_PGP_PASSPHRASE: ${{ secrets.MILL_PGP_PASSPHRASE }}
MILL_PGP_SECRET_BASE64: ${{ secrets.MILL_PGP_SECRET_BASE64 }}
MILL_SONATYPE_PASSWORD: ${{ secrets.MILL_SONATYPE_PASSWORD }}
MILL_SONATYPE_USERNAME: ${{ secrets.MILL_SONATYPE_USERNAME }}
Where MILL_PGP_PASSPHRASE
, MILL_PGP_SECRET_BASE64
, MILL_SONATYPE_PASSWORD
, and
MILL_SONATYPE_USERNAME
configured for the repository’s or organization’s Github Actions
workflows. See
Using Secrets in Github Actions
for more details.
Non-Staging Releases (classic Maven uploads)
If the site does not support staging releases as oss.sonatype.org
and s01.oss.sonatype.org
do (for
example, a self-hosted OSS nexus site), you can pass in the
--stagingRelease false
option to simply upload release artifacts to corresponding
maven path under sonatypeUri
instead of staging path.
mill mill.scalalib.PublishModule/ \
foo.publishArtifacts \
lihaoyi:$SONATYPE_PASSWORD \
--sonatypeUri http://example.company.com/release \
--stagingRelease false