sbt 1.5.0-M2


Hi everyone. On behalf of the sbt project, I am happy to announce sbt 1.5.0-M1. This is the fifth feature release of sbt 1.x, a binary compatible release focusing on new features. sbt 1.x is released under Semantic Versioning, and the plugins are expected to work throughout the 1.x series.

The headline features of sbt 1.5.0 are:

  • Scala 3 support
  • Eviction error
  • Deprecation of sbt 0.13 syntax

How to upgrade

You can upgrade to sbt 1.5.0-M2 by putting the following in project/


Scala 3 support

syntactic Scalafix rule for unified slash syntax


I was able to hack together a syntactic Scalafix rule to convert build.sbt to unified slash syntax.


Make sure your project is on git or make a backup.

$ cs install scalafix
$ export PATH="$PATH:$HOME/Library/Application Support/Coursier/bin"
$ scalafix --rules= *.sbt project/*.scala

It might not be precise, but it surely beats doing it by hand.

git bisecting scala/scala


git bisecting is a useful technique to locate the source of a bug. For scala/scala in particular, can save a lot of time by using the pre-build compiler artifacts on the Scala CI Artifactory.

sbt 1.4.7


I'm happy to announce sbt 1.4.7 patch release is available. Full release note is here -

How to upgrade

Download the official sbt launcher from SDKMAN or download from

In addition, the sbt version used for your build is upgraded by putting the following in project/


This mechanism allows that sbt 1.4.7 is used only for the builds that you want.


enforcing Semantic Versioning with sbt-strict-update

ThisBuild / scalaVersion := "2.13.3"
ThisBuild / libraryDependencySchemes += "org.typelevel" %% "cats-effect" % "early-semver"
lazy val root = (project in file("."))
    name := "demo",
    libraryDependencies ++= List(
      "org.http4s" %% "http4s-blaze-server" % "0.21.11",
      "org.typelevel" %% "cats-effect" % "3.0-8096649",

Now if Rob tries to compile this build, he should get:

sbt:demo> compile
[warn] There may be incompatibilities among your library dependencies; run 'evicted' to see detailed eviction warnings.
[error] stack trace is suppressed; run last update for the full output
[error] (update) found version conflict(s) in library dependencies; some are suspected to be binary incompatible:
[error]   * org.typelevel:cats-effect_2.13:3.0-8096649 (early-semver) is selected over {2.2.0, 2.0.0, 2.0.0, 2.2.0}
[error]       +- demo:demo_2.13:0.1.0-SNAPSHOT                      (depends on 3.0-8096649)
[error]       +- org.http4s:http4s-core_2.13:0.21.11                (depends on 2.2.0)
[error]       +- io.chrisdavenport:vault_2.13:2.0.0                 (depends on 2.0.0)
[error]       +- io.chrisdavenport:unique_2.13:2.0.0                (depends on 2.0.0)
[error]       +- co.fs2:fs2-core_2.13:2.4.5                         (depends on 2.2.0)
[error] Total time: 0 s, completed Dec 13, 2020 11:53:31 PM

auto publish sbt plugin from GitHub Actions

name: Release
      - '*'
    runs-on: ubuntu-latest
      # define Java options for both official sbt and sbt-extras
      JAVA_OPTS: -Xms2048M -Xmx2048M -Xss6M -XX:ReservedCodeCacheSize=256M -Dfile.encoding=UTF-8
      JVM_OPTS:  -Xms2048M -Xmx2048M -Xss6M -XX:ReservedCodeCacheSize=256M -Dfile.encoding=UTF-8
    - name: Checkout
      uses: actions/checkout@v2
    - name: Setup Scala
      uses: olafurpg/setup-scala@v10
        java-version: "adopt@1.8"
    - name: Coursier cache
      uses: coursier/cache-action@v5
    - name: Test
      run: |
        sbt test packagedArtifacts
    - name: Release
        BINTRAY_USER: ${{ secrets.BINTRAY_USER }}
        BINTRAY_PASS: ${{ secrets.BINTRAY_PASS }}
        PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }}
        PGP_SECRET: ${{ secrets.PGP_SECRET }}
        CI_CLEAN: clean
        CI_RELEASE: publishSigned
        CI_SONATYPE_RELEASE: version
      run: |
        sbt ci-release

scopt 4


scopt 4.0.0 is cross published for the following build matrix:

Scala JVM JS (1.x) JS (0.6.x) Native (0.4.0-M2) Native (0.3.x)
3.0.0-M2 n/a n/a n/a
3.0.0-M1 n/a n/a n/a
2.13.x n/a n/a
2.12.x n/a n/a

Here's how functional DSL looks like in scopt 4:

import scopt.OParser
val builder = OParser.builder[Config]
val parser1 = {
  import builder._
    head("scopt", "4.x"),
    // option -f, --foo
    opt[Int]('f', "foo")
      .action((x, c) => c.copy(foo = x))
      .text("foo is an integer property"),
    // more options here...
// OParser.parse returns Option[Config]
OParser.parse(parser1, args, Config()) match {
  case Some(config) =>
    // do something
  case _ =>
    // arguments are bad, error message will have been displayed

Instead of calling methods on OptionParser, the functional DSL first creates a builder based on your specific Config datatype, and calls opt[A](...) functions that returns OParser[A, Config].

These OParser[A, Config] parsers can be composed using OParser.sequence(...).


talk: Scala 3: Python 3 or Easiest Upgrade Ever? by Daniel Spiewak

With the release of Scala 3 just around the corner and a large fraction of the library ecosystem now fully tested and releasing against that version, it's worth looking at the verdict on what this upgrade means for end users of Scala. In this talk, we will look at what has been surprisingly easy and what has been difficult in the process of migrating existing projects from Scala 2.13 to Scala 3.0, as well as sample a bit of what we can look forward to as industrial users of Scala once we make the (surprisingly short) leap.

talk: Equality in Scala by Eugene Yokota

I'll give a talk on equality in Scala. Through untangling this one seemingly simple yet complicated concept of ==, we will trace back the ancestral roots of Scala as a language, and how the design has evolved over the course of its history to achieve its ideals. This first talk is meant to be an ice-breaker to initiate conversations about different language design. The format for future meetings will be determined accordingly.

Syndicate content