Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 20 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,19 @@ addSbtPlugin("org.scala-lang.modules" % "scala-module-plugin" % "1.0.6")
Then, in your `build.sbt` add:

```
scalaModuleSettings
import ScalaModulePlugin._

scalaModuleSettings // in a multi-project build, you might want to apply these settings only to the
// main project (example: scala-parallel-collections)

name := "<module name>"
repoName := "<GitHub repo name>" // the repo under github.com/scala/, only required if different from name
organization := "<org>" // only required if different from "org.scala-lang.modules"
version := "<module version>"

// The plugin uses `scalaVersionsByJvm` to set `crossScalaVersions` according to the JVM major version.
// The `scalaVersion` is set to `crossScalaVersions.value.head`.
scalaVersionsByJvm := {
// The plugin uses `scalaVersionsByJvm` to set `crossScalaVersions in ThisBuild` according to the JVM major version.
// The `scalaVersion in ThisBuild` is set to `crossScalaVersions.value.head`.
scalaVersionsByJvm in ThisBuild := {
val v211 = "2.11.11"
val v212 = "2.12.2"
val v213 = "2.13.0-M1"
Expand All @@ -32,8 +35,7 @@ scalaVersionsByJvm := {
6 -> List(v211 -> true),
7 -> List(v211 -> false),
8 -> List(v212 -> true, v213 -> true, v211 -> false),
9 -> List(v212, v213, v211).map(_ -> false)
)
9 -> List(v212, v213, v211).map(_ -> false))
}

mimaPreviousVersion := Some("1.0.3") // enables MiMa (`None` by default, which disables it)
Expand All @@ -43,6 +45,18 @@ OsgiKeys.exportPackage := Seq(s"<exported package>;version=${version.value}")
// Other settings
```

These additional settings are enabled by `scalaModuleSettings`:
- `scalacOptions in (Compile, compile) ++= Seq("-feature", "-deprecation", "-unchecked", "-Xlint")`
- A `projectName.properties` file is generated and packaged
- `fork in Test := true` to work around some classpath clashes with scala-xml
- `publishTo` sonatype, credentials file expected in `~/.ivy2/.credentials`
- POM and OSGi metadata

The following settings are also available:
- `enableOptimizer` adds `-opt:l:classpath` or `-optimize` to `scalacOptions in (Compile, compile)`,
depending on the Scala version
- `disablePublishing` is useful for multi-project builds for projects that should not be published

## Cutting a new release

- Sign in to Bintray (https://bintray.com/login) or create an "Open Source" account (https://bintray.com/signup/oss)
Expand Down
2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version=0.13.13
sbt.version=0.13.15
87 changes: 59 additions & 28 deletions src/main/scala/ScalaModulePlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,56 +3,85 @@ import Keys._
import com.typesafe.sbt.osgi.{OsgiKeys, SbtOsgi}
import com.typesafe.tools.mima.plugin.{MimaPlugin, MimaKeys}, MimaKeys._

object ScalaModulePlugin extends Plugin {
val repoName = settingKey[String]("The name of the repository under github.com/scala/.")
val mimaPreviousVersion = settingKey[Option[String]]("The version of this module to compare against when running MiMa.")
val scalaVersionsByJvm = settingKey[Map[Int, List[(String, Boolean)]]]("For a Java major version (6, 8, 9), a list of Scala version and a flag indicating whether to use this combination for publishing.")
object ScalaModulePlugin extends AutoPlugin {
val repoName = settingKey[String]("The name of the repository under github.com/scala/.")
val mimaPreviousVersion = settingKey[Option[String]]("The version of this module to compare against when running MiMa.")
val scalaVersionsByJvm = settingKey[Map[Int, List[(String, Boolean)]]]("For a Java major version (6, 8, 9), a list of a Scala version and a flag indicating whether to use this combination for publishing.")

private val canRunMima = taskKey[Boolean]("Decides if MiMa should run.")
private val runMimaIfEnabled = taskKey[Unit]("Run MiMa if mimaPreviousVersion and the module can be resolved against the current scalaBinaryVersion.")
// Settings applied to the entire build when the plugin is loaded.

lazy val scalaModuleSettings: Seq[Setting[_]] = Seq(
repoName := name.value,

mimaPreviousVersion := None,
override def trigger = allRequirements

scalaVersionsByJvm := Map.empty,
override def buildSettings: Seq[Setting[_]] = Seq(
scalaVersionsByJvm := Map.empty,

crossScalaVersions := {
crossScalaVersions in ThisBuild := {
val OneDot = """1\.(\d).*""".r // 1.6, 1.8
val Maj = """(\d+).*""".r // 9
val javaVersion = System.getProperty("java.version") match {
case OneDot(n) => n.toInt
case Maj(n) => n.toInt
case v => throw new RuntimeException(s"Unknown Java version: $v")
}
val isTravisPublishing = Option(System.getenv("TRAVIS_TAG")).getOrElse("").trim.nonEmpty
val scalaVersions = scalaVersionsByJvm.value.getOrElse(javaVersion, Nil) collect {

val isTravis = Option(System.getenv("TRAVIS")).exists(_ == "true") // `contains` doesn't exist in Scala 2.10
val isTravisPublishing = Option(System.getenv("TRAVIS_TAG")).exists(_.trim.nonEmpty)

val byJvm = scalaVersionsByJvm.value
if (byJvm.isEmpty)
throw new RuntimeException(s"Make sure to define `scalaVersionsByJvm in ThisBuild` in `build.sbt` in the root project, using the `ThisBuild` scope.")

val scalaVersions = byJvm.getOrElse(javaVersion, Nil) collect {
case (v, publish) if !isTravisPublishing || publish => v
}
if (scalaVersions.isEmpty) {
if (isTravisPublishing) {
if (isTravis) {
sLog.value.warn(s"No Scala version in `scalaVersionsByJvm` in build.sbt needs to be released on Java major version $javaVersion.")
// Exit successfully, don't fail the (travis) build. This happens for example if `openjdk7`
// is part of the travis configuration for testing, but it's not used for releasing against
// any Scala version.
System.exit(0)
} else
throw new RuntimeException(s"No Scala version for Java major version $javaVersion. Adjust `scalaVersionsByJvm` in build.sbt.")
throw new RuntimeException(s"No Scala version for Java major version $javaVersion. Change your Java version or adjust `scalaVersionsByJvm` in build.sbt.")
}
scalaVersions
},

scalaVersion := crossScalaVersions.value.head,
scalaVersion in ThisBuild := crossScalaVersions.value.head
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JFYI the in ThisBuild is redundant here by virtue of this being in buildSettings.

That's also why the RHS here isn't (crossScalaVersions in ThisBuild).value.head because buildSettings maps the RHS too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aha thanks! will add a code comment.

)

/**
* Enable `-opt:l:classpath` or `-optimize`, depending on the scala version.
*/
lazy val enableOptimizer: Setting[_] = scalacOptions in (Compile, compile) += {
val ScalaMaj = """2\.(\d+)\..*""".r
val ScalaMaj(scalaMaj) = scalaVersion.value
if (scalaMaj.toInt >= 12) "-opt:l:classpath" else "-optimize"
}

/**
* Practical for multi-project builds.
*/
lazy val disablePublishing: Seq[Setting[_]] = Seq(
publishArtifact := false,
// The above is enough for Maven repos but it doesn't prevent publishing of ivy.xml files
publish := {},
publishLocal := {},
publishTo := Some(Resolver.file("devnull", file("/dev/null")))
)

/**
* To be included in the main sbt project of a Scala module.
*/
lazy val scalaModuleSettings: Seq[Setting[_]] = Seq(
repoName := name.value,

organization := "org.scala-lang.modules",
mimaPreviousVersion := None,

// so we don't have to wait for sonatype to synch to maven central when deploying a new module
resolvers += Resolver.sonatypeRepo("releases"),
organization := "org.scala-lang.modules",

// don't use for doc scope, scaladoc warnings are not to be reckoned with
// TODO: turn on for nightlies, but don't enable for PR validation... "-Xfatal-warnings"
scalacOptions in compile ++= Seq("-optimize", "-feature", "-deprecation", "-unchecked", "-Xlint"),
scalacOptions in (Compile, compile) ++= Seq("-feature", "-deprecation", "-unchecked", "-Xlint"),

// Generate $name.properties to store our version as well as the scala version used to build
resourceGenerators in Compile += Def.task {
Expand All @@ -76,8 +105,6 @@ object ScalaModulePlugin extends Plugin {
// alternatively, manage the scala instance as shown at the end of this file (commented)
fork in Test := true,

publishArtifact in Test := false,

// maven publishing
publishTo := Some(
if (version.value.trim.endsWith("SNAPSHOT")) Resolver.sonatypeRepo("snapshots")
Expand Down Expand Up @@ -114,7 +141,7 @@ object ScalaModulePlugin extends Plugin {
) ++ mimaSettings ++ scalaModuleOsgiSettings

// adapted from https://github.com/typesafehub/migration-manager/blob/0.1.6/sbtplugin/src/main/scala/com/typesafe/tools/mima/plugin/SbtMima.scala#L69
def artifactExists(organization: String, name: String, scalaBinaryVersion: String, version: String, ivy: IvySbt, s: TaskStreams): Boolean = {
private def artifactExists(organization: String, name: String, scalaBinaryVersion: String, version: String, ivy: IvySbt, s: TaskStreams): Boolean = {
val moduleId = new ModuleID(organization, s"${name}_$scalaBinaryVersion", version)
val moduleSettings = InlineConfiguration(
"dummy" % "test" % "version",
Expand All @@ -135,7 +162,11 @@ object ScalaModulePlugin extends Plugin {
}
}

lazy val mimaSettings: Seq[Setting[_]] = MimaPlugin.mimaDefaultSettings ++ Seq(
// Internal task keys for the MiMa settings
private val canRunMima = taskKey[Boolean]("Decides if MiMa should run.")
private val runMimaIfEnabled = taskKey[Unit]("Run MiMa if mimaPreviousVersion and the module can be resolved against the current scalaBinaryVersion.")

private lazy val mimaSettings: Seq[Setting[_]] = MimaPlugin.mimaDefaultSettings ++ Seq(
// manual cross-versioning because https://github.com/typesafehub/migration-manager/issues/62
mimaPreviousArtifacts := Set(organization.value % s"${name.value}_${scalaBinaryVersion.value}" % mimaPreviousVersion.value.getOrElse("dummy")),

Expand Down Expand Up @@ -165,9 +196,9 @@ object ScalaModulePlugin extends Plugin {
)

// a setting-transform to turn the regular version into something osgi can deal with
val osgiVersion = version(_.replace('-', '.'))
private val osgiVersion = version(_.replace('-', '.'))

lazy val scalaModuleOsgiSettings = SbtOsgi.osgiSettings ++ Seq(
private lazy val scalaModuleOsgiSettings = SbtOsgi.osgiSettings ++ Seq(
OsgiKeys.bundleSymbolicName := s"${organization.value}.${name.value}",
OsgiKeys.bundleVersion := osgiVersion.value,

Expand Down