Building Java sources with SBT and Nexus-deployment

Just a small example to show how to use sbt instead of classical maven to build a java program and deploy it to Nexus repo manager.

Software and versions:

SBT 0.13.15 http://www.scala-sbt.org/download.html
Nexus OSS 3.3.2-02 https://www.sonatype.com/download-oss-sonatype

The project:

.
├── build.sbt
├── README.md
├── src
│   ├── main
│   │   └── java
│   │       └── eu
│   │           └── christophburmeister
│   │               └── playground
│   │                   └── App.java
│   └── test
│       └── java
│           └── eu
│               └── christophburmeister
│                   └── playground
│                       └── AppTest.java

The only interesting part is build.sbt (the „sbt pom“). Where maven uses xml, sbt uses scala for implementing the build process;

// Project name (artifact name in Maven)
name := "example-java-sbt"

// orgnization name (e.g., the package name of the project)
organization := "eu.christophburmeister.playground"

version := "0.0.1-SNAPSHOT"

// project description
description := "example project for scala build of java sources"

// Enables publishing to maven repo
publishMavenStyle := true

// Define location of publishing target
// local deployment (similar to "mvn install")
// publishTo := Some(Resolver.file("file",  new File( "/data/local-maven-repo" )))
// remote deployment (similar to "mvn deploy")
publishTo := {
  val nexus = "http://localhost:8081"
  if (isSnapshot.value)
    Some("snapshots" at nexus + "/repository/sbt-snapshots")
  else
    Some("releases"  at nexus + "/repository/sbt-releases")
}

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

// Do not append Scala versions to the generated artifacts
crossPaths := false

// This forbids including Scala related libraries into the dependency
// If you do not want to include scala-library.jar (Scala’s core library) within the generated pacakge, set autoScalaLibrary to false. 
// This enables building pure-java project with sbt.
autoScalaLibrary := false

// library dependencies. (orginization name) % (project name) % (version) % (scope)
libraryDependencies ++= Seq(
   "junit" % "junit" % "3.8.1" % "test"  // Test-only dependency
)

For remote deployment to Nexus of course, you need credentials. Those credentials can be put to build.sbt but should not. Instead you can use the mechanism that is shown in build.sbt where you reference ~/.sbt/nexus-credentials.properties:

realm=Sonatype Nexus Repository Manager
host=localhost
user=admin
password=admin123

This is similar to the mechanism in Maven’s settings.xml

Running the compilation and execute the tests:

$ sbt clean compile test
[...]
[info] Loading project definition from /home/christoph/workspace/example-java-sbt/project
[info] Set current project to example-java-sbt (in build file:/home/christoph/workspace/example-java-sbt/)
[success] Total time: 0 s, completed 25.06.2017 15:27:17
[info] Updating {file:/home/christoph/workspace/example-java-sbt/}example-java-sbt...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Compiling 1 Java source to /home/christoph/workspace/example-java-sbt/target/classes...
[success] Total time: 1 s, completed 25.06.2017 15:27:17
[info] Compiling 1 Java source to /home/christoph/workspace/example-java-sbt/target/test-classes...
[success] Total time: 0 s, completed 25.06.2017 15:27:18

Running the packaging

$ sbt clean compile test package
[...]
[info] Loading project definition from /home/christoph/workspace/example-java-sbt/project
[info] Set current project to example-java-sbt (in build file:/home/christoph/workspace/example-java-sbt/)
[success] Total time: 0 s, completed 25.06.2017 15:29:32
[info] Updating {file:/home/christoph/workspace/example-java-sbt/}example-java-sbt...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Compiling 1 Java source to /home/christoph/workspace/example-java-sbt/target/classes...
[success] Total time: 1 s, completed 25.06.2017 15:29:33
[info] Compiling 1 Java source to /home/christoph/workspace/example-java-sbt/target/test-classes...
[success] Total time: 0 s, completed 25.06.2017 15:29:33
[info] Packaging /home/christoph/workspace/example-java-sbt/target/example-java-sbt-0.0.1-SNAPSHOT.jar ...
[info] Done packaging.
[success] Total time: 0 s, completed 25.06.2017 15:29:33

Running the deployment (aka publishing) where the packaging is already included:

$ sbt clean compile test publish
[...]
[info] Loading project definition from /home/christoph/workspace/example-java-sbt/project
[info] Set current project to example-java-sbt (in build file:/home/christoph/workspace/example-java-sbt/)
[success] Total time: 0 s, completed 25.06.2017 15:32:50
[info] Updating {file:/home/christoph/workspace/example-java-sbt/}example-java-sbt...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Compiling 1 Java source to /home/christoph/workspace/example-java-sbt/target/classes...
[success] Total time: 1 s, completed 25.06.2017 15:32:51
[info] Compiling 1 Java source to /home/christoph/workspace/example-java-sbt/target/test-classes...
[success] Total time: 0 s, completed 25.06.2017 15:32:51
[info] Packaging /home/christoph/workspace/example-java-sbt/target/example-java-sbt-0.0.1-SNAPSHOT-sources.jar ...
[info] Done packaging.
[info] Main Java API documentation to /home/christoph/workspace/example-java-sbt/target/api...
[info] Packaging /home/christoph/workspace/example-java-sbt/target/example-java-sbt-0.0.1-SNAPSHOT.jar ...
[info] Done packaging.
[info] Wrote /home/christoph/workspace/example-java-sbt/target/example-java-sbt-0.0.1-SNAPSHOT.pom
[info] :: delivering :: eu.christophburmeister.playground#example-java-sbt;0.0.1-SNAPSHOT :: 0.0.1-SNAPSHOT :: integration :: Sun Jun 25 15:32:51 CEST 2017
[info] 	delivering ivy file to /home/christoph/workspace/example-java-sbt/target/ivy-0.0.1-SNAPSHOT.xml
[info] Loading source file /home/christoph/workspace/example-java-sbt/src/main/java/eu/christophburmeister/playground/App.java...
[info] Constructing Javadoc information...
[info] Standard Doclet version 1.8.0_131
[info] Building tree for all the packages and classes...
[info] Generating /home/christoph/workspace/example-java-sbt/target/api/eu/christophburmeister/playground/App.html...
[info] Generating /home/christoph/workspace/example-java-sbt/target/api/eu/christophburmeister/playground/package-frame.html...
[info] Generating /home/christoph/workspace/example-java-sbt/target/api/eu/christophburmeister/playground/package-summary.html...
[info] Generating /home/christoph/workspace/example-java-sbt/target/api/eu/christophburmeister/playground/package-tree.html...
[info] Generating /home/christoph/workspace/example-java-sbt/target/api/constant-values.html...
[info] Building index for all the packages and classes...
[info] Generating /home/christoph/workspace/example-java-sbt/target/api/overview-tree.html...
[info] Generating /home/christoph/workspace/example-java-sbt/target/api/index-all.html...
[info] Generating /home/christoph/workspace/example-java-sbt/target/api/deprecated-list.html...
[info] Building index for all classes...
[info] Generating /home/christoph/workspace/example-java-sbt/target/api/allclasses-frame.html...
[info] Generating /home/christoph/workspace/example-java-sbt/target/api/allclasses-noframe.html...
[info] Generating /home/christoph/workspace/example-java-sbt/target/api/index.html...
[info] Generating /home/christoph/workspace/example-java-sbt/target/api/help-doc.html...
[info] Main Java API documentation successful.
[info] Packaging /home/christoph/workspace/example-java-sbt/target/example-java-sbt-0.0.1-SNAPSHOT-javadoc.jar ...
[info] Done packaging.
[info] 	published example-java-sbt to http://localhost:8081/repository/sbt-snapshots/eu/christophburmeister/playground/example-java-sbt/0.0.1-SNAPSHOT/example-java-sbt-0.0.1-SNAPSHOT.pom
[info] 	published example-java-sbt to http://localhost:8081/repository/sbt-snapshots/eu/christophburmeister/playground/example-java-sbt/0.0.1-SNAPSHOT/example-java-sbt-0.0.1-SNAPSHOT.jar
[info] 	published example-java-sbt to http://localhost:8081/repository/sbt-snapshots/eu/christophburmeister/playground/example-java-sbt/0.0.1-SNAPSHOT/example-java-sbt-0.0.1-SNAPSHOT-sources.jar
[info] 	published example-java-sbt to http://localhost:8081/repository/sbt-snapshots/eu/christophburmeister/playground/example-java-sbt/0.0.1-SNAPSHOT/example-java-sbt-0.0.1-SNAPSHOT-javadoc.jar
[success] Total time: 1 s, completed 25.06.2017 15:32:52

Et voila:

Fork me on github 🙂 https://github.com/muthai/example-java-sbt

References:

  • https://janzhou.org/2015/10/29/use-sbt-and-git-to-create-your-own-maven-repository.html
  • http://www.scala-sbt.org/0.13/docs/Publishing.html
  • http://alvinalexander.com/scala/sbt-how-to-compile-run-package-scala-project
  • http://xerial.org/blog/2014/03/24/sbt/
  • http://www.scala-sbt.org/0.13/docs/Using-Sonatype.html
  • https://stackoverflow.com/questions/21453768/put-operations-to-url-failed-with-status-code-405-method-not-allowed-ivy-remo
  • http://www.cakesolutions.net/teamblogs/2012/01/28/publishing-sbt-projects-to-nexus
  • http://www.cakesolutions.net/teamblogs/publishing-artefacts-to-oss-sonatype-nexus-using-sbt-and-travis-ci
  • https://stackoverflow.com/questions/16425639/sbt-publish-to-corporate-nexus-repository-unauthorized
  • http://jessicaaustin.net/405-error-when-deploying-to-maven-repository/