Skip to content

Add sbt-version-policy #137

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 3, 2021
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
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ The plugin also brings in
- sbt-header to automate copyright header maintenance
- sbt-mima-plugin to maintain binary compatibility
- sbt-osgi, if enabled with `scalaModuleOsgiSettings`
- sbt-version-policy to check the versioning policy

## Usage

Expand All @@ -53,7 +54,7 @@ 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"

scalaModuleMimaPreviousVersion := Some("1.0.0") // enables MiMa (`None` by default, which disables it)
versionPolicyIntention := Compatibility.BinaryAndSourceCompatible // enables MiMa (`Compatibility.None` by default, which disables it)

OsgiKeys.exportPackage := Seq(s"<exported package>;version=${version.value}")

Expand All @@ -77,7 +78,7 @@ The following settings are also available:

## Set up tag-based publishing

The instructions here are a summary of the readme in https://github.com/olafurpg/sbt-ci-release
The instructions here are a summary of the readme in https://github.com/olafurpg/sbt-ci-release and https://github.com/scalacenter/sbt-version-policy

- Create a fresh GPG key: `gpg --gen-key`
- Real name: use "project-name bot"
Expand All @@ -97,3 +98,5 @@ The instructions here are a summary of the readme in https://github.com/olafurpg
- ubuntu: `gpg --armor --export-secret-keys $LONG_ID | base64 -w0`
- `SONATYPE_PASSWORD`: need that one
- `SONATYPE_USERNAME`: that one too

- Run `versionCheck` in the publishing process: `sbt versionCheck ci-release`
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ developers := List(Developer("", "", "", url("https://scala-lang.org"))

addSbtPlugin("com.typesafe.sbt" % "sbt-osgi" % "0.9.6")
addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.6.0")
addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.9.2")
addSbtPlugin("com.dwijnand" % "sbt-travisci" % "1.2.0") // set scalaVersion and crossScalaVersions
addSbtPlugin("com.geirsson" % "sbt-ci-release" % "1.5.7") // set version, scmInfo, publishing settings
addSbtPlugin("ch.epfl.scala" % "sbt-version-policy" % "1.2.1")
61 changes: 19 additions & 42 deletions src/main/scala/ScalaModulePlugin.scala
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
package com.lightbend.tools.scalamoduleplugin

import com.typesafe.sbt.osgi.{OsgiKeys, SbtOsgi}
import com.typesafe.tools.mima.plugin.MimaKeys._
import com.typesafe.tools.mima.plugin.MimaPlugin
import de.heikoseeberger.sbtheader.HeaderPlugin.autoImport.{HeaderLicense, headerLicense}
import sbt.Keys._
import sbt._
import sbt.internal.librarymanagement.IvySbt
import sbt.librarymanagement.ivy.IvyDependencyResolution
import sbt.librarymanagement.{UnresolvedWarningConfiguration, UpdateConfiguration}
import sbt.{Def, _}
import sbtdynver.DynVerPlugin
import sbtdynver.DynVerPlugin.autoImport.dynverGitDescribeOutput
import xerial.sbt.Sonatype.autoImport.{sonatypeProfileName, sonatypeSessionName}
import sbtversionpolicy.SbtVersionPolicyPlugin.autoImport.{Compatibility, versionPolicyCheck, versionPolicyIgnoredInternalDependencyVersions, versionPolicyIntention}

object ScalaModulePlugin extends AutoPlugin {
object autoImport {
val scalaModuleRepoName = settingKey[String]("The name of the repository under github.com/scala/.")
val scalaModuleAutomaticModuleName = settingKey[Option[String]]("Automatic-Module-Name setting for manifest")
@deprecated("Previous version is now automatically computed by sbt-version-policy. Setting this key has no effect", "2.4.0")
val scalaModuleMimaPreviousVersion = settingKey[Option[String]]("The version of this module to compare against when running MiMa.")
val scalaModuleEnableOptimizerInlineFrom = settingKey[String]("The value passed to -opt-inline-from by `enableOptimizer` on 2.13 and higher.")
}
Expand All @@ -36,7 +33,7 @@ object ScalaModulePlugin extends AutoPlugin {
dv.copy(ref = sbtdynver.GitRef(dv.ref.value.split('#').head)))),
)

// Settings added to the global scope
// Settings added to the project scope
override def projectSettings: Seq[Setting[_]] = Seq(
// The staging profile is called `org.scala-lang`, the default is `org.scala-lang.modules`
sonatypeProfileName := "org.scala-lang",
Expand All @@ -53,6 +50,12 @@ object ScalaModulePlugin extends AutoPlugin {
},
)

// Global settings
override def globalSettings: Seq[Def.Setting[_]] = Seq(
// Since we use sbt-dynver, see https://github.com/scalacenter/sbt-version-policy#how-to-integrate-with-sbt-dynver
versionPolicyIgnoredInternalDependencyVersions := Some("^\\d+\\.\\d+\\.\\d+\\+\\d+".r)
)

/**
* Enable `-opt:l:inline`, `-opt:l:project` or `-optimize`, depending on the scala version.
*/
Expand Down Expand Up @@ -167,47 +170,21 @@ object ScalaModulePlugin extends AutoPlugin {
// a setting-transform to turn the regular version into something osgi can deal with
private val osgiVersion = version(_.replace('-', '.'))

// adapted from https://github.com/lightbend/migration-manager/blob/0.3.0/sbtplugin/src/main/scala/com/typesafe/tools/mima/plugin/SbtMima.scala#L112
private def artifactExists(organization: String, name: String, scalaBinaryVersion: String, version: String, ivy: IvySbt, s: TaskStreams): Boolean = {
val moduleId = ModuleID(organization, s"${name}_$scalaBinaryVersion", version)
val depRes = IvyDependencyResolution(ivy.configuration)
val module = depRes.wrapDependencyInModule(moduleId)
val updateConf = UpdateConfiguration() withLogging UpdateLogging.DownloadOnly
val reportEither = depRes.update(module, updateConf, UnresolvedWarningConfiguration(), s.log)
reportEither.fold(_ => false, _ => true)
}

// 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.")
// Internal task keys for the versionPolicy settings
private val runVersionPolicyCheckIfEnabled = taskKey[Unit]("Run versionPolicyCheck if versionPolicyIntention is not set to Compatibility.None.")

private lazy val mimaSettings: Seq[Setting[_]] = Seq(
scalaModuleMimaPreviousVersion := None,

// We're not using `%%` here in order to support both jvm and js projects (cross version `_2.12` / `_sjs0.6_2.12`)
mimaPreviousArtifacts := scalaModuleMimaPreviousVersion.value.map(v => organization.value % moduleName.value % v cross crossVersion.value).toSet,

canRunMima := {
val log = streams.value.log
scalaModuleMimaPreviousVersion.value match {
case None =>
log.warn("MiMa will NOT run because no mimaPreviousVersion is provided.")
false
case Some(mimaVer) =>
val exists = artifactExists(organization.value, name.value, scalaBinaryVersion.value, mimaVer, ivySbt.value, streams.value)
if (!exists)
log.warn(s"""MiMa will NOT run because the previous artifact "${organization.value}" % "${name.value}_${scalaBinaryVersion.value}" % "$mimaVer" could not be resolved (note the binary Scala version).""")
exists
}
},
versionPolicyIntention := Compatibility.None,

runMimaIfEnabled := Def.taskDyn({
if (canRunMima.value) Def.task { mimaReportBinaryIssues.value }
else Def.task { () }
runVersionPolicyCheckIfEnabled := Def.taskDyn({
if (versionPolicyIntention.value != Compatibility.None) Def.task { versionPolicyCheck.value }
else Def.task {
streams.value.log.warn("versionPolicyCheck will NOT run because versionPolicyIntention is set to Compatibility.None.")
}
}).value,

Test / test := {
runMimaIfEnabled.value
runVersionPolicyCheckIfEnabled.value
(Test / test).value
}
)
Expand Down