Search code examples
scalasbtpublishingsnapshotsbt-plugin

Is it possible to reject publish if SNAPSHOT dependencies are used in SBT?


I keep accidentally publishing my internal project still referencing internal SNAPSHOTs, but it would be very helpful if there was an SBT plugin that would fail to publish if you are relying on any SNAPSHOT dependencies. Is anyone aware of such a plugin or feature in SBT?


Solution

  • Here's how you can write such plugin.

    output

    > publish
    [info] :: delivering :: com.example#b_2.10;0.1.0 :: 0.1.0 :: release :: Fri Jan 13 15:50:53 EST 2017
    [info]  delivering ivy file to /xxx/b/target/scala-2.10/ivy-0.1.0.xml
    [info] Wrote /xxx/b/target/scala-2.10/b_2.10-0.1.0.pom
    [info] Wrote /xxx/a/target/scala-2.10/a_2.10-0.1.0.pom
    [info] :: delivering :: com.example#a_2.10;0.1.0 :: 0.1.0 :: release :: Fri Jan 13 15:50:53 EST 2017
    [info]  delivering ivy file to /xxx/a/target/scala-2.10/ivy-0.1.0.xml
    [trace] Stack trace suppressed: run last b/*:publishConfiguration for the full output.
    [trace] Stack trace suppressed: run last a/*:publishConfiguration for the full output.
    [error] (b/*:publishConfiguration) SNAPSHOT found in classpath:
    [error] com.eed3si9n:treehugger_2.10:0.2.4-SNAPSHOT:compile->default;compile->compile;compile->runtime;compile->default(compile);compile->master
    [error] (a/*:publishConfiguration) SNAPSHOT found in classpath:
    [error] com.eed3si9n:treehugger_2.10:0.2.4-SNAPSHOT:compile->default;compile->compile;compile->runtime;compile->default(compile);compile->master
    [error] com.example:c_2.10:0.1.0-SNAPSHOT:compile->compile;compile->default(compile)
    [error] io.netty:netty-all:4.1.8.Final-SNAPSHOT:compile->default;compile->compile;compile->runtime;compile->default(compile);compile->master
    [error] Total time: 0 s, completed Jan 13, 2017 3:50:53 PM
    

    project/build.properties

    sbt.version = 0.13.13
    

    project/DepsVerifyPlugin.scala

    import sbt._
    import Keys._
    
    object DepsVerifyPlugin extends sbt.AutoPlugin {
      override def requires = plugins.JvmPlugin
      override def trigger = allRequirements
      override def projectSettings = Seq(
        publishConfiguration := {
          val old = publishConfiguration.value
          val ur = update.value
          ur.configuration("compile") foreach { compileReport =>
            val allModules = compileReport.allModules
            val snapshotDeps = allModules filter { _.revision contains "SNAPSHOT" }
            if (snapshotDeps.nonEmpty) {
              sys.error(
                "SNAPSHOT found in classpath:\n" +
                snapshotDeps.mkString("\n")
              )
            }
          }
          old
        }
        )
    }
    

    build.sbt

    val commonSettings: Seq[Setting[_]] = Seq(
        organization in ThisBuild := "com.example",
        scalaVersion in ThisBuild := "2.10.6",
        version      in ThisBuild := "0.1.0",
        resolvers += Resolver.sonatypeRepo("public"),
        publishTo := Some(Resolver.file("file",  new File(Path.userHome.absolutePath+"/test-repo")))
      )
    
    val netty = "io.netty" % "netty-all" % "4.1.8.Final-SNAPSHOT"
    val treehugger = "com.eed3si9n" %% "treehugger" % "0.2.4-SNAPSHOT"
    
    lazy val root = (project in file("."))
      .aggregate(a, b, c)
      .settings(
        commonSettings,
        name := "Hello",
        publish := ()
      )
    
    lazy val a = (project in file("a"))
      .dependsOn(b, c)
      .settings(
        commonSettings,
        libraryDependencies += netty
      )
    
    lazy val b = (project in file("b"))
      .settings(
        commonSettings,
        libraryDependencies += treehugger
      )
    
    lazy val c = (project in file("c"))
      .settings(
        commonSettings,
        version := "0.1.0-SNAPSHOT",
        publish := ()
      )