sbt publish

Synopsis

sbt [query / ] publish
sbt [query / ] publishSigned
sbt [query / ] publishLocal
sbt [query / ] publishM2

Description

The publish family of tasks provide means for compiling and publishing your project. Publishing in this context consists of uploading a descriptor, such as a Maven POM or ivy.xml, and artifacts, such as a JAR or war file, to a repository so that other projects can specify your project as a dependency.

  • The publish task publishes your project to a remote repository, such as JFrog Artifactory or Sonatype Nexus instance.
  • The publishSigned task, enabled using sbt-pgp plugin, is used to publish GPG-signed artifacts.
  • The publishLocal task publishes your project to the Ivy local file repository, which is usually located at $HOME/.ivy2/local/. You can then use this project from other projects on the same machine.
  • The publishM2 task publishes your project to the local Maven repository.

There's a specific recipe for publishing to the Central Repo.

Skip publishing

To avoid publishing a project, add the following setting to the subprojects that you want to skip:

publish / skip := true

Common use case is to prevent publishing of the root project.

Define the repository

To specify the repository, assign a repository to publishTo and optionally set the publishing style. For example, to upload to Nexus:

publishTo := Some("Sonatype Snapshots Nexus" at "https://oss.sonatype.org/content/repositories/snapshots")

To publish to a local maven repository:

publishTo := Some(MavenCache("local-maven", file("path/to/maven-repo/releases")))

To publish to a local Ivy repository:

publishTo := Some(Resolver.file("local-ivy", file("path/to/ivy-repo/releases")))

If you're publishing the Central Repository, you will also have to select the right repository depending on your artifacts: SNAPSHOT versions go to the central-snapshots repository while other versions go to the local staging repository. Doing this selection can be done by using the value of the version setting:

publishTo := {
  val centralSnapshots = "https://central.sonatype.com/repository/maven-snapshots/"
  if version.value.endsWith("-SNAPSHOT") then Some("central-snapshots" at centralSnapshots)
  else localStaging.value
}

Publishing locally

The publishLocal task will publish to the "local" Ivy repository. By default, this is at $HOME/.ivy2/local/. Other builds on the same machine can then list the project as a dependency. For example, if the project you are publishing has configuration parameters like:

organization := "com.example"
version := "0.1-SNAPSHOT"
name := "hello"

Then another build on the same machine can depend on it:

libraryDependencies += "com.example" %% "hello" % "0.1-SNAPSHOT"

The version number you select must end with SNAPSHOT, or you must change the version number each time you publish to indicate that it's a changing artifact.

Warning

Generally the use of SNAPSHOT dependencies should be avoided beyond testing on a single machine since it makes dependency resolution slower and the build non-repeatable.

Similar to publishLocal, publishM2 task will publish the user's Maven local repository. This is at the location specified by $HOME/.m2/settings.xml or at $HOME/.m2/repository/ by default. Another build would require Resolver.mavenLocal to resolve out of it:

resolvers += Resolver.mavenLocal

Credentials

There are two ways to specify credentials for such a repository.

The first and better way is to load them from a file, for example:

credentials += Credentials(Path.userHome / ".sbt" / ".credentials")

The credentials file is a properties file with keys realm, host, user, and password. For example:

realm=Sonatype Nexus Repository Manager
host=my.artifact.repo.net
user=admin
password=admin123

The second way is to specify them inline:

credentials += Credentials("Sonatype Nexus Repository Manager", "my.artifact.repo.net", "admin", "admin123")

Note

Credentials matching is done using both: realm and host keys. The realm key is the HTTP WWW-Authenticate header's realm directive, which is part of the response of HTTP servers for HTTP Basic Authentication. For a given repository, this can be found by reading all the headers received. For example:

curl -D - my.artifact.repo.net

Cross-publishing

To support multiple incompatible Scala versions, use projectMatrix and publish (see Cross building setup).

Overriding the publishing convention

By default sbt will publish your artifact with the binary version of Scala you're using. For example if your project is using Scala 2.13.x your example artifact would be published under example_2.13. This is often what you want, but if you're publishing a pure Java artifact or a compiler plugin you'll want to change the CrossVersion. See the Cross building setup page for more details under the Publishing convention section.

Published artifacts

By default, the main binary JAR, a sources JAR, and a API documentation JAR are published. You can declare other types of artifacts to publish and disable or modify the default artifacts. See the Artifact page for details.

Version scheme

versionScheme setting tracks the version scheme of the build:

versionScheme := Some("early-semver")

The supported values are "early-semver", "pvp", "semver-spec", and "strict". sbt will include this information into pom.xml and ivy.xml as a property.

  • Some("early-semver"): Early Semantic Versioning that would keep binary compatibility across patch updates within 0.Y.z (for instance 0.13.0 and 0.13.2). Once it goes 1.0.0, it follows the regular Semantic Versioning where 1.1.0 is bincompat with 1.0.0.
  • Some("semver-spec"): Semantic Versioning where all 0.y.z are treated as initial development (no bincompat guarantees).
  • Some("pvp"). Haskell Package Versioning Policy where X.Y are treated as major version.
  • Some("strict"). Requires exact match of version.

This information will be annotated into the pom.xml file, which helps downstream projects determine whether a version conflict is safe to resolve or not. See Preventing version conflicts with versionScheme (2021).

Modifying the generated POM

When publishMavenStyle is true, a POM is generated by the makePom action and published to the repository instead of an Ivy file. This POM file may be altered by changing a few settings. Set pomExtra to provide XML (scala.xml.NodeSeq) to insert directly into the generated pom. For example:

pomExtra := <something></something>

There is also a pomPostProcess setting that can be used to manipulate the final XML before it is written. It's type is Node => Node.

pomPostProcess := { (node: Node) =>
  ....
}

makePom adds to the POM any Maven-style repositories you have declared. You can filter these by modifying pomRepositoryFilter, which by default excludes local repositories. To instead only include local repositories:

pomIncludeRepository := { (repo: MavenRepository) =>
  repo.root.startsWith("file:")
}