Helps you find:
Undeclared dependencies
// in your build.sbt ...
libraryDependencies +=
  "org.typelevel" %% "cats-effect" % "1.0.0"// somewhere in your src/main/scala ...
import cats.effect.IO
import cats.data.NonEmptyList
val foo: IO[Unit] = IO {
  println(NonEmptyList.of(1, 2, 3))
}Unused dependencies
// in your build.sbt ...
libraryDependencies +=
  "org.scalatest" %% "scalatest" % "3.0.5"declared
actual
undeclared compile dependencies
declared
actual
unused compile dependencies
libraryDependencies
How do we work out what libraries our project actually needs in order to compile?
First idea: bytecode analysis + jar traversal
import cats.data._
object Foo {
  val valid = Validated.valid("hello")
}
Constant pool: ... #23 = Utf8 cats/data/Validated$ #24 = Class #23 // cats/data/Validated$ ...
First idea: bytecode analysis + jar traversal
First idea: bytecode analysis + jar traversal
TERRIBLE IDEA
sbt:example> inspect compile
[info] Task: xsbti.compile.CompileAnalysis
[info] Description:
[info]  Compiles sources.
compile analysis? 🤔
printActualDeps := {
  compile.in(Compile).value
    .asInstanceOf[sbt.internal.inc.Analysis]
    .relations
    .allLibraryDeps
    .foreach(println)
}sbt:example> printActualDeps /Users/chris/.ivy2/cache/org.typelevel/cats-effect_2.12/jars/cats-effect_2.12-0.10.1.jar /Users/chris/.ivy2/cache/org.typelevel/cats-core_2.12/jars/cats-core_2.12-1.2.0.jar /Users/chris/.ivy2/cache/com.chuusai/shapeless_2.12/bundles/shapeless_2.12-2.3.3.jar /Users/chris/.sbt/boot/scala-2.12.6/lib/scala-library.jar /Users/chris/.ivy2/cache/org.http4s/http4s-blaze-server_2.12/jars/http4s-blaze-server_2.12-0.18.16.jar /Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/jre/lib/rt.jar /Users/chris/.ivy2/cache/com.google.guava/guava/bundles/guava-26.0-jre.jar
// no need to add anything to project/plugins.sbt 
enablePlugins(SbtPlugin)
scalaVersion := "2.12.8"
organization := "chris"
libraryDependencies ++= Seq(
  // whatever libraries you need ...
)// src/main/scala/hello/HelloPlugin.scala
package hello
import sbt._
object HelloPlugin extends AutoPlugin {
  object autoImport {
    val sayHello = taskKey[Unit]("say hello")
  }
  // if you want your plugin to be enable automatically
  override def trigger = allRequirements
  override def projectSettings = Seq(
    autoImport.sayHello := {
      println("Hello world!")
    }
  )
}
Publish your plugin locally:
Add it to another sbt project:
$ sbt publishLocal
// project/plugins.sbt
addSbtPlugin("chris" % "sbt-hello-world" % "0.1.0-SNAPSHOT")And try it out:
sbt:sbt-example> sayHello Hello world!
... is really easy!
// project/plugins.sbt
addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.4")
addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.9")// build.sbt
organization := "com.foo.bar"
description := "my amazing plugin"
licenses += ("Apache-2.0", url("..."))
publishMavenStyle := false
bintrayRepository := "my-sbt-plugins"
bintrayOrganization in bintray := Nonesbt 0.13.x and 1.x are very similar,
but lots of classes got moved around
Type aliases in sbt version-specific package objects
package object explicitdeps {
  type Logger = sbt.util.Logger
  type ModuleID = sbt.librarymanagement.ModuleID
  type Binary = sbt.librarymanagement.Binary
  type Analysis = sbt.internal.inc.Analysis
  ...
}
package object explicitdeps {
  type Logger = sbt.Logger
  type ModuleID = sbt.ModuleID
  type Binary = sbt.CrossVersion.Binary
  type Analysis = sbt.inc.Analysis
  ...
}
src/main/scala-sbt-1.0/...
src/main/scala-sbt-0.13/...
everything else goes
in src/main/scala
Shared code must be valid in both 2.12.x and 2.10.x
package object explicitdeps {
  ...
  implicit class NodeSeqOps(nodeSeq: scala.xml.NodeSeq) {
    def \@(attributeName: String): String = 
      (nodeSeq \ ("@" + attributeName)).text
  }
}
src/main/scala-sbt-0.13/...
Add shims in version-specific package object:
LambdAle CFP opens soon!