Java Packaging & Publishing
This page will discuss common topics around packaging and publishing your Java projects for others to use.
Building Executable Assemblies with AssemblyModule
Mill’s built in .assembly
task makes it easy to generate an executable assembly
jar from any JVM module. You can also customize the assembly jar as shown below:
package build
import mill._, javalib._
import mill.javalib.Assembly._
object foo extends JavaModule {
def moduleDeps = Seq(bar)
def assemblyRules = Seq(
// all application.conf files will be concatenated into single file
Rule.Append("application.conf"),
// all *.conf files will be concatenated into single file
Rule.AppendPattern(".*\\.conf"),
// all *.temp files will be excluded from a final jar
Rule.ExcludePattern(".*\\.temp"),
// the `shapeless` package will be relocated under the `shade` package
Rule.Relocate("shapeless.**", "shade.shapless.@1")
)
}
object bar extends JavaModule {}
The most common way of configuring an assembly is
excluding some files from a final jar (like signature files,
and manifest files from library jars), and merging duplicated files (for
instance reference.conf
files from library dependencies). This is
done by overriding def assemblyRules
as shown above
By default mill excludes all *.sf
, *.dsa
, *.rsa
, and
META-INF/MANIFEST.MF
files from assembly, and concatenates all
reference.conf
files. You can also define your own merge/exclude rules.
> ./mill foo.assembly
> unzip -p ./out/foo/assembly.dest/out.jar application.conf || true
Bar Application Conf
Foo Application Conf
> java -jar ./out/foo/assembly.dest/out.jar
Loaded application.conf from resources:...
...Foo Application Conf
...Bar Application Conf
Note that when running the assembly directly via ./out.jar
, you can configure
JVM flags via the JAVA_OPTS
environment variable, and select the JVM
to use via JAVA_HOME
.
> JAVA_OPTS=-Dtest.property=1337 ./out/foo/assembly.dest/out.jar
Loaded test.property: 1337
Building Executable Assemblies with RepackageModule
An alternative way to produce self-executable assemblies is the RepackageModule
which used the Spring Boot Tools suite.
Instead of copying and merging dependencies classes and resources into a flat jar file, it embeds all dependencies as-is in the final jar.
One of the pros of this approach is, that all dependency archives are kept unextracted, which makes later introspection for checksums, authorship and copyright questions easier.
package build
import mill._, javalib._, publish._
import mill.javalib.repackage.RepackageModule
trait MyModule 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"))
)
def mvnDeps = Seq(mvn"org.thymeleaf:thymeleaf:3.1.1.RELEASE")
object test extends JavaTests with TestModule.Junit4
}
object foo extends MyModule with RepackageModule { (1)
def moduleDeps = Seq(bar, qux)
}
object bar extends MyModule {
def moduleDeps = Seq(qux)
}
object qux extends MyModule
1 | Add the mill.javalib.repackage.RepackageModule to the executable module. |
> mill foo.run
Foo.value: <h1>hello</h1>
Bar.value: <p>world</p>
Qux.value: 31337
> mill show foo.repackagedJar
".../out/foo/repackagedJar.dest/out.jar"
> ./out/foo/repackagedJar.dest/out.jar
Foo.value: <h1>hello</h1>
Bar.value: <p>world</p>
Qux.value: 31337
> unzip -l ./out/foo/repackagedJar.dest/out.jar "BOOT-INF/lib*"
...BOOT-INF/lib/thymeleaf-3.1.1.RELEASE.jar
...BOOT-INF/lib/ognl-3.3.4.jar
...BOOT-INF/lib/attoparser-2.0.6.RELEASE.jar
...BOOT-INF/lib/unbescape-1.1.6.RELEASE.jar
...BOOT-INF/lib/slf4j-api-2.0.5.jar
...BOOT-INF/lib/javassist-3.29.0-GA.jar
...BOOT-INF/lib/qux-0.0.1.jar
...BOOT-INF/lib/bar-0.0.1.jar
Futher notes:
-
a small wrapper application needs to be added, which is run as entry point and transparently manages loading the embedded jars and running your
main
method. This works for all Java (also Scala or Kotlin) applications. -
It’s not necessary to use the Spring Framework in the application.
-
The resulting jar is a self-executable application, but it might not suitable to be used on the classpath of other applications.
-
Since the final jar produced with the
RepackageModule.repackagedJar
task often contains significantly less ZIP entries then the jar file produced with.assembly
, it’s possible to workaround an issue whereJavaModule.assembly
cannot produce executable assemblies due to some JVM limitations in ZIP file handling of large files.
Building Native Image Binaries with Graal VM
package build
import mill._, javalib._
import mill.define.ModuleRef
object foo extends JavaModule with NativeImageModule {
def jvmWorker = ModuleRef(JvmWorkerGraalvm)
def nativeImageOptions = Seq("--no-fallback")
}
object JvmWorkerGraalvm extends JvmWorkerModule {
def jvmId = "graalvm-community:17.0.7"
}
This example uses NativeImageModule
to generate a native executable using Graal VM.
We recommend you configure a specific JDK version
via a custom JvmWorkerModule
overriding def jvmId
(shown above), as not every JVM can build Graal native images.
> ./mill show foo.nativeImage
GraalVM Native Image: Generating...native-executable...
Finished generating...native-executable...
> ./out/foo/nativeImage.dest/native-executable
Hello, World!
For another example building a slightly less trivial project into a Graal native image, see below:
package build
import mill._, javalib._
import mill.define.ModuleRef
object foo extends JavaModule with NativeImageModule {
def mvnDeps = Seq(
mvn"net.sourceforge.argparse4j:argparse4j:0.9.0",
mvn"org.thymeleaf:thymeleaf:3.1.1.RELEASE",
mvn"org.slf4j:slf4j-nop:2.0.7"
)
def jvmWorker = ModuleRef(JvmWorkerGraalvm)
def nativeImageOptions = Seq(
"--no-fallback",
"-H:IncludeResourceBundles=net.sourceforge.argparse4j.internal.ArgumentParserImpl",
"-Os"
)
}
object JvmWorkerGraalvm extends JvmWorkerModule {
def jvmId = "graalvm-community:23.0.1"
}
This example shows how to generate native images for projects using third-party
libraries, in this case ArgParse4J and Thymeleaf. ArgParse4J does use some dynamic
resource loading and reflection, and so we need to pass the -H:IncludeResourceBundles
flag to nativeImageOptions
in order to be compatible. We also demonstrate setting
using -Os
to optimize for the smallest binary size,
which is available in the graalvm-community:23
JDK selected above.
> ./mill show foo.nativeImage
> ./out/foo/nativeImage.dest/native-executable --text hello-world
<h1>hello-world</h1>
You can see the Graal documentation to see what flags are available:
Or access the native-image
compiler directly via show foo.nativeImageTool
if you want to experiment it or view its --help
text to see what you need to pass to
nativeImageOptions
:
> ./mill show foo.nativeImageTool # mac/linux
".../bin/native-image"
> ./mill show foo.nativeImageTool # windows
".../bin/native-image.cmd"
For more details on using Graal, check the this blog post:
Java App and Bundles using jlink
This example illustrates how to use Mill to generate a runtime image using the jlink
tool.
Starting with JDK 9, jlink
bundles Java app code with a stripped-down version of the JVM.
package build
import mill._, javalib._
import mill.javalib.Assembly._
import mill.scalalib.JlinkModule
object foo extends JavaModule with JlinkModule {
def jlinkModuleName: T[String] = Task { "foo" }
def jlinkModuleVersion: T[Option[String]] = Task { Option("1.0") }
def jlinkCompressLevel: T[String] = Task { "2" }
}
Most of the work is done by the trait JlinkModule
in two steps:
-
It uses the
jmod
tool to create ajlink.jmod
file for the main Java module. The main Java module is typically the module containing themainClass
.
If your build file doesn’t explicitly specify a mainClass
, JlinkModule
will infer it from JavaModule
, which is its parent trait.
See Specifying the Main Class to learn more on how to influence the inference process.
You can explicitly specify a mainClass
like so in your build file:
def mainClass: T[Option[String]] = { Some("com.foo.app.Main") }
-
It then uses the
jlink
tool, to link the previously createdjlink.jmod
with a runtime image.
With respect to the jlinkCompressLevel
option, on recent builds of OpenJDK and its descendants,
jlink
will accept [0
, 1
, 2
] but it will issue a deprecation warning.
Valid values on OpenJDK range between: ["zip-0" - "zip-9"].
The version of jlink that ships with the Oracle JDK will only accept [0 , 1 , 2 ]
as valid values for compression, with 0 being "no compression"
and 2 being "ZIP compression".
|
To use a specific JDK, first set your JAVA_HOME
environment variable prior to running the build.
export JAVA_HOME=/Users/mac/.sdkman/candidates/java/17.0.9-oracle/
> mill foo.jlinkAppImage
> mill show foo.jlinkAppImage
".../out/foo/jlinkAppImage.dest/jlink-runtime"
> ./out/foo/jlinkAppImage.dest/jlink-runtime/bin/jlink
... foo.Bar main
INFO: Hello World!
Java Installers using jpackage
This example illustrates how to use Mill to generate a native package/installer
using the jpackage
tool.
package build
import mill._, javalib._
import mill.javalib.Assembly._
import mill.scalalib.JpackageModule
object foo extends JavaModule with JpackageModule {
def jpackageType = "app-image"
def assemblyRules = Seq(
// all application.conf files will be concatenated into single file
Rule.Append("application.conf"),
// all *.conf files will be concatenated into single file
Rule.AppendPattern(".*\\.conf")
)
}
JPMS (Java Platform Module System) is a modern distribution format that was designed to avoid several of the shortcomings of the ubiquitous JAR format, especially "JAR Hell".
A defining characteristic of module-based Java applications based on the JPMS format
is that a module-info.java
must be defined at the root of the module’s source file hierarchy.
The module-info.java
must explicitly list modules that it depends on, and also list
packages that it exports, to make the integrity of these relationships easy to verify,
both at compile-time and run-time.
Starting with version 14, the JDK ships with the jpackage
tool which can
assemble any module-based Java application into a native package/installer.
The above build file expects the following project layout:
build.mill foo/ src/ Foo.java Bar.java module-info.java
> mill foo.jpackageAppImage
> mill show foo.jpackageAppImage
".../out/foo/jpackageAppImage.dest/image"
The term Module is also used in Mill to refer to Mill Modules.
This is not to be confused with Java app code structured as modules according to the JPMS format.
|
The JpackageModule
trait will infer most of the options needed to assemble a native
package/installer, but you can still customize its output. In our example, we specified:
def jpackageType = "pkg"
This tells jpackage
to generate a .pkg
, which is the native installer format on macOS.
Valid values on macOS are: dmg
, pkg
and app-image
.
jpackage doesn’t support cross-build to a different OS/CPU combination than
the one you the build is running on. For example, the jpackage binary shipped with a macOS JDK
cannot be used to produce a native installer for another OS like Windows or Linux.
|
On macOS, jpackageType
accepts 3 values: "dmg" or "pkg" or "app-image" (default).
-
Setting
def jpackageType = "dmg"
will produce:
> ls -l ./out/foo/jpackageAppImage.dest/image ... foo-1.0.dmg
-
Setting
def jpackageType = "pkg"
will produce:
> ls -l ./out/foo/jpackageAppImage.dest/image ... foo-1.0.pkg
-
Setting
def jpackageType = "app-image"
will produce:
> ls -l ./out/foo/jpackageAppImage.dest/image ... foo.app/ ./out/foo/jpackageAppImage.dest/image/foo.app/Contents/MacOS/foo ... foo.Foo readConf INFO: Loaded application.conf from resources: Foo Application Conf ... foo.Bar ... INFO: Hello World application started successfully
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...
publishLocal
accepts options like --doc=false
and --sources=false
,
to disable publishing javadoc JARs and source JARs, which are generated and
published by default. This can be helpful if you’re not interested in javadoc JARs,
and javadoc generation fails, and you would rather address those errors later for example.
publishLocal
also accepts --transitive=true
, to also publish locally the
transitive dependencies of the module being published. This ensures the module
can be resolved from the local repository, with no missing dependencies.
publishLocal
publishes the artifacts to the ~/.ivy2/local
folder on your
machine, allowing them to be resolved by other projects and build tools. This
is useful as a lightweight way of testing out the published artifacts, without
the setup overhead and long latencies of publishing artifacts globally accessible
to anyone in the world.
publishLocal
accepts options like --doc=false
and --sources=false
,
to disable publishing javadoc JARs and source JARs, which are generated and
published by default. This can be helpful if you’re not interested in javadoc JARs,
and javadoc generation fails or takes too much time. When using Scala 2, disabling
javadoc generation can bring large speedups, given it entails compiling your code
a second time.
publishLocal
also accepts --transitive=true
, to also publish locally the
transitive dependencies of the module being published. This ensures the module
can be resolved from the local repository, with no missing dependencies.
Publishing to Sonatype Maven Central
package build
import mill._, javalib._, publish._
import mill.scalalib.SonatypeCentralPublishModule
object foo extends JavaModule with SonatypeCentralPublishModule {
def scalaVersion = "2.13.8"
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"))
)
}
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"))
)
// add Revapi config JSON file(s)
override def revapiConfigFiles: T[Seq[PathRef]] = Task.Sources("conf/revapi.json")
// add folder containing logback.xml
override def revapiClasspath = Task { super.revapiClasspath() ++ confClasspath() }
def confClasspath = Task.Sources("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
|
This example configured for publishing to Sonatype Maven Central via
Central Portal. Extends SonatypeCentralPublishModule
which provides
simplified publishing tasks without requiring Nexus repository manager.
Instructions for Publishing to Maven Central via Central Portal
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:
# Sonatype Central Portal needs your public key to be uploaded so it can use for verification of artifacts from their end.
#
# Send your public key to ubuntu server so Sonatype Maven Central can use for verification of the artifacts
gpg --keyserver keyserver.ubuntu.com --send-keys $LONG_ID
#
# Check the server for information about the public key. information will be displayed if found
gpg --keyserver keyserver.ubuntu.com --recv-keys $LONG_ID
#
# 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
mill.scalalib.SonatypeCentralPublishModule/
:
> mill mill.scalalib.SonatypeCentralPublishModule/
You can also specify individual modules you want to publish in two ways:
> mill foo.publishSonatypeCentral
> mill mill.scalalib.SonatypeCentralPublishModule/ --publishArtifacts foo.publishArtifacts
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.SonatypeCentralPublishModule/
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.
Instructions for Publishing to Maven Central via Legacy OSSHR (Deprecated)
Publishing via the legacy OSSRH (OSS Repository Hosting) is deprecated and will reach end-of-life on June 30, 2025, due to the retirement of Sonatype’s Nexus Repository Manager v2. Sonatype now recommends using the Central Portal for all new publishing. Migration is strongly encouraged to avoid disruptions. For full details, see the OSSRH Sunset Announcement. |
Just like publishing via the Central Portal requires a GPG key and publish secrets, publishing via the legacy OSSHR(OSS Repository Hosting) also requires them.
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/ --publishArtifacts 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/ \
--publishArtifacts foo.publishArtifacts \
--sonatypeCreds lihaoyi:$SONATYPE_PASSWORD \
--sonatypeUri http://example.company.com/release \
--stagingRelease false
SonatypeCentralPublishModule
Configurations
This module provides settings and a CLI interface for publishing artifacts to Sonatype Maven Central.
You can configure it through your build.mill
file or by passing command-line options to it.
Module-Level Settings
You can override default publishing settings in your build.mill like this:
object mymodule extends SonatypeCentralPublishModule {
override def sonatypeCentralGpgArgs: T[String] = "--batch, --yes, -a, -b"
override def sonatypeCentralConnectTimeout: T[Int] = 5000
override def sonatypeCentralReadTimeout: T[Int] = 60000
override def sonatypeCentralAwaitTimeout: T[Int] = 120 * 1000
override def sonatypeCentralShouldRelease: T[Boolean] = true
...
}
Argument Reference
publishAll
The publishAll
task can be called from the CLI. If a required value is not provided via the CLI option,
it will fall back to an environment variable (if available) or raise an error if missing.
The ./mill mill.scalalib.SonatypeCentralPublishModule/publishAll
takes the following options:
username
: The username for calling the Sonatype Central publishing api. Defaults to the SONATYPE_USERNAME
environment variable if unset. If neither the parameter nor the environment variable are set, an error will be thrown.
password
: The password for calling the Sonatype Central publishing api. Defaults to the SONATYPE_PASSWORD
environment variable if unset. If neither the parameter nor the environment variable are set, an error will be thrown.
gpgArgs
: Arguments to pass to the gpg package for signing artifacts. Uses the MILL_PGP_PASSPHRASE
environment variable if set. Default: [--passphrase=$MILL_PGP_PASSPHRASE], --no-tty, --pinentry-mode, loopback, --batch, --yes, -a, -b
.
publishArtifacts
: The command for generating all publishable artifacts (ex. __.publishArtifacts
). Required.
readTimeout
: The timeout for receiving a response from Sonatype Central after the initial connection has occurred. Default: 60000.
awaitTimeout
: The overall timeout for all retries (including exponential backoff) of the bundle upload. Default: 120 * 1000.
connectTimeout
: The timeout for the initial connection to Sonatype Central if there is no response. Default: 5000.
shouldRelease
: Whether the bundle should be automatically released when uploaded to Sonatype Central. If false
, the bundle will still be uploaded, but users will need to manually log in to Sonatype Central and publish the bundle from the portal. Default: true
bundleName
: If set, all packages will be uploaded in a single bundle with the given name. If unset, packages will be uploaded separately. Recommended bundle name syntax: groupName-artifactId-versionNumber. As an example, if publishing the com.lihaoyi
requests
package, without the bundle name, four different bundles will be uploaded, one for each scala version supported. With a bundle name of com.lihaoyi-requests-<new_version>
, a single bundle will be uploaded that contains all packages across scala versions. It is recommended to set the bundle name, so that packages can be verified and deployed together. Default: No bundle name is set and packages will be uploaded separately
Example command
$ mill -i \ mill.scalalib.SonatypeCentralPublishModule/publishAll \ --username myusername \ --password mypassword \ --gpgArgs --passphrase=$MILL_PGP_PASSPHRASE,--no-tty,--pinentry-mode,loopback,--batch,--yes,-a,-b \ --publishArtifacts __.publishArtifacts \ --readTimeout 36000 \ --awaitTimeout 36000 \ --connectTimeout 36000 \ --shouldRelease false \ --bundleName com.lihaoyi-requests:1.0.0