build.sbt (308 lines of code) (raw):
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* license agreements; and to You under the Apache License, version 2.0:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* This file is part of the Apache Pekko project, derived from Akka.
*/
import com.github.pjfanning.pekkobuild._
import net.bzzt.reproduciblebuilds.ReproducibleBuildsPlugin.reproducibleBuildsCheckResolver
import org.apache.pekko.grpc.{ Dependencies, NoPublish, PekkoCoreDependency, PekkoHttpDependency }
import org.apache.pekko.grpc.Dependencies.Versions.{ scala212, scala213 }
import org.apache.pekko.grpc.ProjectExtensions._
import org.apache.pekko.grpc.build.ReflectiveCodeGen
import com.typesafe.tools.mima.core._
import sbt.Keys.scalaVersion
sourceDistName := "apache-pekko-grpc"
sourceDistIncubating := false
ThisBuild / versionScheme := Some(VersionScheme.SemVerSpec)
ThisBuild / resolvers += Resolver.ApacheMavenStagingRepo
commands := commands.value.filterNot { command =>
command.nameOption.exists { name =>
name.contains("sonatypeRelease") || name.contains("sonatypeBundleRelease")
}
}
ThisBuild / reproducibleBuildsCheckResolver := Resolver.ApacheMavenStagingRepo
// So that gRPC is properly styled
ThisBuild / apacheSonatypeArtifactNameProcessor := apacheSonatypeArtifactNameProcessor.value.andThen {
_.replaceAll("Grpc", "gRPC")
}
val pekkoPrefix = "pekko-grpc"
val pekkoGrpcRuntimeName = s"$pekkoPrefix-runtime"
lazy val mkBatAssemblyTask = taskKey[File]("Create a Windows bat assembly")
// gradle plugin compatibility (avoid `+` in snapshot versions)
(ThisBuild / dynverSeparator) := "-"
val pekkoGrpcCodegenId = s"$pekkoPrefix-codegen"
lazy val codegen = Project(id = "codegen", base = file("codegen"))
.enablePlugins(SbtTwirl, BuildInfoPlugin)
.enablePlugins(ReproducibleBuildsPlugin)
.disablePlugins(MimaPlugin)
.settings(Dependencies.codegen)
.settings(resolvers += Resolver.sbtPluginRepo("releases"))
.settings(MetaInfLicenseNoticeCopy.assemblySettings)
.settings(
name := s"$pekkoPrefix-codegen",
mkBatAssemblyTask := {
val file = assembly.value
Assemblies.mkBatAssembly(file)
},
buildInfoKeys ++= Seq[BuildInfoKey](organization, name, version, scalaVersion, sbtVersion),
buildInfoKeys += "runtimeArtifactName" -> pekkoGrpcRuntimeName,
buildInfoKeys += "pekkoVersion" -> Dependencies.Versions.pekko,
buildInfoKeys += "pekkoHttpVersion" -> Dependencies.Versions.pekkoHttp,
buildInfoKeys += "grpcVersion" -> Dependencies.Versions.grpc,
buildInfoKeys += "googleProtocVersion" -> Dependencies.Versions.googleProtoc,
buildInfoKeys += "googleProtobufJavaVersion" -> Dependencies.Versions.googleProtobufJava,
buildInfoPackage := "org.apache.pekko.grpc.gen",
(Compile / assembly / artifact) := {
val art = (Compile / assembly / artifact).value
art.withClassifier(Some("assembly"))
},
(assembly / mainClass) := Some("org.apache.pekko.grpc.gen.Main"),
(assembly / assemblyOption) := (assembly / assemblyOption).value.withPrependShellScript(
Some(sbtassembly.AssemblyPlugin.defaultUniversalScript(shebang = true))),
(assembly / assemblyMergeStrategy) := {
case PathList("META-INF", "MANIFEST.MF") => MergeStrategy.discard
case PathList("META-INF", "versions", _, "module-info.class") => MergeStrategy.discard
case "LICENSE" | "LICENSE.txt" | "NOTICE" => MergeStrategy.discard
case _ => MergeStrategy.deduplicate
},
crossScalaVersions := Dependencies.Versions.CrossScalaForPlugin,
scalaVersion := scala212,
Compile / unmanagedSourceDirectories ++= {
if (scalaBinaryVersion.value == "2.12") {
Seq.empty
} else {
Seq(
project.base / "src" / "main" / "scala-2.13+")
}
})
.settings(addArtifact(Compile / assembly / artifact, assembly))
.settings(addArtifact(sbt.Artifact(pekkoGrpcCodegenId, "bat", "bat", "bat"), mkBatAssemblyTask))
val mimaCompareVersion = "1.0.2"
lazy val runtime = Project(id = "runtime", base = file("runtime"))
.addPekkoModuleDependency("pekko-stream", "", PekkoCoreDependency.default)
.addPekkoModuleDependency("pekko-http-core", "", PekkoHttpDependency.default)
.addPekkoModuleDependency("pekko-http", "", PekkoHttpDependency.default)
.addPekkoModuleDependency("pekko-discovery", "", PekkoCoreDependency.default)
.addPekkoModuleDependency("pekko-http-cors", "", PekkoHttpDependency.default)
.addPekkoModuleDependency("pekko-testkit", "test", PekkoCoreDependency.default)
.addPekkoModuleDependency("pekko-stream-testkit", "test", PekkoCoreDependency.default)
.settings(Dependencies.runtime)
.settings(VersionGenerator.settings)
.settings(MetaInfLicenseNoticeCopy.runtimeSettings)
.settings(
crossScalaVersions := Dependencies.Versions.CrossScalaForLib,
scalaVersion := Dependencies.Versions.CrossScalaForLib.head)
.settings(
name := pekkoGrpcRuntimeName,
mimaFailOnNoPrevious := true,
mimaPreviousArtifacts := Set(
organization.value %% "pekko-grpc-runtime" % mimaCompareVersion),
AutomaticModuleName.settings("pekko.grpc.runtime"),
ReflectiveCodeGen.generatedLanguages := Seq("Scala"),
ReflectiveCodeGen.extraGenerators := Seq("ScalaMarshallersCodeGenerator"),
PB.protocVersion := Dependencies.Versions.googleProtoc)
.enablePlugins(org.apache.pekko.grpc.build.ReflectiveCodeGen)
.enablePlugins(ReproducibleBuildsPlugin)
/** This could be an independent project - or does upstream provide this already? didn't find it.. */
val pekkoGrpcProtocPluginId = s"$pekkoPrefix-scalapb-protoc-plugin"
lazy val scalapbProtocPlugin = Project(id = "scalapb-protoc-plugin", base = file("scalapb-protoc-plugin"))
.disablePlugins(MimaPlugin)
.settings(MetaInfLicenseNoticeCopy.assemblySettings)
.settings(
name := s"$pekkoPrefix-scalapb-protoc-plugin",
libraryDependencies += {
Dependencies.Compile.scalapbCompilerPlugin
},
mkBatAssemblyTask := {
val file = assembly.value
Assemblies.mkBatAssembly(file)
},
(Compile / assembly / artifact) := {
val art = (Compile / assembly / artifact).value
art.withClassifier(Some("assembly"))
},
(assembly / mainClass) := Some("org.apache.pekko.grpc.scalapb.Main"),
(assembly / assemblyOption) := (assembly / assemblyOption).value.withPrependShellScript(
Some(sbtassembly.AssemblyPlugin.defaultUniversalScript(shebang = true))),
(assembly / assemblyMergeStrategy) := {
case PathList("META-INF", "MANIFEST.MF") => MergeStrategy.discard
case PathList("META-INF", "versions", _, "module-info.class") => MergeStrategy.discard
case "LICENSE" | "LICENSE.txt" | "NOTICE" => MergeStrategy.discard
case _ => MergeStrategy.deduplicate
})
.settings(
crossScalaVersions := Dependencies.Versions.CrossScalaForLib,
scalaVersion := Dependencies.Versions.CrossScalaForLib.head)
.settings(addArtifact(Compile / assembly / artifact, assembly))
.settings(addArtifact(sbt.Artifact(pekkoGrpcProtocPluginId, "bat", "bat", "bat"), mkBatAssemblyTask))
.enablePlugins(ReproducibleBuildsPlugin)
lazy val mavenPlugin = Project(id = "maven-plugin", base = file("maven-plugin"))
.enablePlugins(org.apache.pekko.grpc.SbtMavenPlugin)
.enablePlugins(ReproducibleBuildsPlugin)
.disablePlugins(MimaPlugin)
.settings(Dependencies.mavenPlugin)
.settings(
name := s"$pekkoPrefix-maven-plugin",
crossPaths := false,
crossScalaVersions := Dependencies.Versions.CrossScalaForPlugin,
scalaVersion := Dependencies.Versions.CrossScalaForPlugin.head)
.dependsOn(codegen)
lazy val sbtPlugin = Project(id = "sbt-plugin", base = file("sbt-plugin"))
.enablePlugins(SbtPlugin)
.enablePlugins(ReproducibleBuildsPlugin)
.disablePlugins(MimaPlugin)
.settings(Dependencies.sbtPlugin)
.settings(
name := s"$pekkoPrefix-sbt-plugin",
/** And for scripted tests: */
scriptedLaunchOpts += ("-Dproject.version=" + version.value),
scriptedLaunchOpts ++= sys.props.collect { case (k @ "sbt.ivy.home", v) => s"-D$k=$v" }.toSeq,
scriptedDependencies := {
val p1 = publishLocal.value
val p2 = (codegen / publishLocal).value
val p3 = (runtime / publishLocal).value
val p4 = (interopTests / publishLocal).value
},
scriptedSbt := "1.10.11",
scriptedBufferLog := false)
.settings(
crossScalaVersions := Dependencies.Versions.CrossScalaForPlugin,
scalaVersion := Dependencies.Versions.CrossScalaForPlugin.head)
.dependsOn(codegen)
lazy val interopTests = Project(id = "interop-tests", base = file("interop-tests"))
.disablePlugins(MimaPlugin)
.addPekkoModuleDependency("pekko-http", "", PekkoHttpDependency.default)
.addPekkoModuleDependency("pekko-slf4j", "", PekkoCoreDependency.default)
.addPekkoModuleDependency("pekko-testkit", "test", PekkoCoreDependency.default)
.addPekkoModuleDependency("pekko-stream-testkit", "test", PekkoCoreDependency.default)
.settings(Dependencies.interopTests)
.settings(
crossScalaVersions := Dependencies.Versions.CrossScalaForLib,
scalaVersion := Dependencies.Versions.CrossScalaForLib.head)
.pluginTestingSettings
.settings(
name := s"$pekkoPrefix-interop-tests",
// All io.grpc servers want to bind to port :8080
parallelExecution := false,
ReflectiveCodeGen.generatedLanguages := Seq("Scala", "Java"),
ReflectiveCodeGen.extraGenerators := Seq("ScalaMarshallersCodeGenerator"),
ReflectiveCodeGen.codeGeneratorSettings ++= Seq("server_power_apis"),
// grpc 1.54.2 brings in extra unnecessary proto files that cause build issues
PB.generate / excludeFilter := new SimpleFileFilter(f => f.getAbsolutePath().contains("envoy")),
PB.protocVersion := Dependencies.Versions.googleProtoc,
// We need to be able to publish locally in order for sbt interopt tests to work
// however this sbt project should not be published to an actual repository
publishLocal / skip := false,
Compile / doc := (Compile / doc / target).value)
.settings(inConfig(Test)(Seq(
reStart / mainClass := (Test / run / mainClass).value, {
import spray.revolver.Actions._
reStart := Def
.inputTask {
restartApp(
streams.value,
reLogTag.value,
thisProjectRef.value,
reForkOptions.value,
(reStart / mainClass).value,
(reStart / fullClasspath).value,
reStartArgs.value,
startArgsParser.parsed)
}
.dependsOn(Compile / products)
.evaluated
}))).enablePlugins(NoPublish)
lazy val benchmarks = Project(id = "benchmarks", base = file("benchmarks"))
.dependsOn(runtime)
.enablePlugins(JmhPlugin)
.disablePlugins(MimaPlugin)
.settings(
name := s"$pekkoPrefix-benchmarks",
crossScalaVersions := Dependencies.Versions.CrossScalaForLib,
scalaVersion := Dependencies.Versions.CrossScalaForLib.head)
.enablePlugins(NoPublish)
lazy val docs = Project(id = "docs", base = file("docs"))
// Make sure code generation is run:
.dependsOn(pluginTesterScala)
.dependsOn(pluginTesterJava)
.enablePlugins(PekkoParadoxPlugin, ParadoxSitePlugin, PreprocessPlugin)
.disablePlugins(MimaPlugin)
.settings(
name := s"$pekkoPrefix-docs",
makeSite := makeSite.dependsOn(LocalRootProject / ScalaUnidoc / doc).value,
pekkoParadoxGithub := Some("https://github.com/apache/pekko-grpc"),
previewPath := (Paradox / siteSubdirName).value,
Preprocess / siteSubdirName := s"api/pekko-grpc/${projectInfoVersion.value}",
Preprocess / sourceDirectory := (LocalRootProject / ScalaUnidoc / unidoc / target).value,
Paradox / siteSubdirName := s"docs/pekko-grpc/${projectInfoVersion.value}",
// Make sure code generation is run before paradox:
(Compile / paradox) := (Compile / paradox).dependsOn(Compile / compile).value,
paradoxGroups := Map("Language" -> Seq("Java", "Scala"), "Buildtool" -> Seq("sbt", "Gradle", "Maven")),
Global / pekkoParadoxIncubatorNotice := None,
Compile / paradoxProperties ++= Map(
"pekko.version" -> Dependencies.Versions.pekko,
"pekko-http.version" -> Dependencies.Versions.pekkoHttp,
"grpc.version" -> Dependencies.Versions.grpc,
"project.url" -> "https://pekko.apache.org/docs/pekko-grpc/current/",
"canonical.base_url" -> "https://pekko.apache.org/docs/pekko-grpc/current",
"scaladoc.scala.base_url" -> "https://www.scala-lang.org/api/current/",
// Apache Pekko
"extref.pekko.base_url" -> s"https://pekko.apache.org/docs/pekko/${Dependencies.Versions.pekkoBinary}/%s",
"scaladoc.org.apache.pekko.base_url" -> s"https://pekko.apache.org/api/pekko/${Dependencies.Versions.pekkoBinary}/",
"javadoc.org.apache.pekko.base_url" -> s"https://pekko.apache.org/japi/pekko/${Dependencies.Versions.pekkoBinary}/",
// Apache Pekko HTTP
"extref.pekko-http.base_url" -> s"https://pekko.apache.org/docs/pekko-http/${Dependencies.Versions.pekkoHttpBinary}/%s",
"scaladoc.org.apache.pekko.http.base_url" -> s"https://pekko.apache.org/api/pekko-http/${Dependencies.Versions.pekkoHttpBinary}/",
"javadoc.org.apache.pekko.http.base_url" -> s"https://pekko.apache.org/japi/pekko-http/${Dependencies.Versions.pekkoHttpBinary}/",
// Apache Pekko gRPC
"scaladoc.org.apache.pekko.grpc.base_url" -> s"/${(Preprocess / siteSubdirName).value}/",
"javadoc.org.apache.pekko.grpc.base_url" -> "" // @apidoc links to Scaladoc
),
apidocRootPackage := "org.apache.pekko",
Compile / paradoxMarkdownToHtml / sourceGenerators += Def.taskDyn {
val targetFile = (Compile / paradox / sourceManaged).value / "license-report.md"
(LocalRootProject / dumpLicenseReportAggregate).map { dir =>
IO.copy(List(dir / "pekko-grpc-root-licenses.md" -> targetFile)).toList
}
}.taskValue)
.settings(
crossScalaVersions := Dependencies.Versions.CrossScalaForLib,
scalaVersion := Dependencies.Versions.CrossScalaForLib.head)
.enablePlugins(NoPublish)
lazy val pluginTesterScala = Project(id = "plugin-tester-scala", base = file("plugin-tester-scala"))
.disablePlugins(MimaPlugin)
.addPekkoModuleDependency("pekko-http-cors", "", PekkoHttpDependency.default)
.addPekkoModuleDependency("pekko-http", "", PekkoHttpDependency.default)
.settings(Dependencies.pluginTester)
.settings(
name := s"$pekkoPrefix-plugin-tester-scala",
fork := true,
PB.protocVersion := Dependencies.Versions.googleProtoc,
crossScalaVersions := Dependencies.Versions.CrossScalaForLib,
scalaVersion := scala212,
ReflectiveCodeGen.codeGeneratorSettings ++= Seq("flat_package", "server_power_apis"))
.pluginTestingSettings
.enablePlugins(NoPublish)
lazy val pluginTesterJava = Project(id = "plugin-tester-java", base = file("plugin-tester-java"))
.disablePlugins(MimaPlugin)
.settings(Dependencies.pluginTester)
.settings(
name := s"$pekkoPrefix-plugin-tester-java",
fork := true,
PB.protocVersion := Dependencies.Versions.googleProtoc,
ReflectiveCodeGen.generatedLanguages := Seq("Java"),
crossScalaVersions := Dependencies.Versions.CrossScalaForLib,
scalaVersion := scala212,
ReflectiveCodeGen.codeGeneratorSettings ++= Seq("server_power_apis"))
.pluginTestingSettings
.enablePlugins(NoPublish)
lazy val root = Project(id = "pekko-grpc", base = file("."))
.enablePlugins(ScalaUnidocPlugin)
.disablePlugins(SitePlugin, MimaPlugin)
.aggregate(
runtime,
codegen,
mavenPlugin,
sbtPlugin,
scalapbProtocPlugin,
interopTests,
pluginTesterScala,
pluginTesterJava,
benchmarks,
docs)
.settings(
name := s"$pekkoPrefix-root",
(Compile / headerCreate / unmanagedSources) := (baseDirectory.value / "project").**("*.scala").get,
// unidoc combines sources and jars from all subprojects and that
// might include some incompatible ones. Depending on the
// classpath order that might lead to scaladoc compilation errors.
// the scalapb compilerplugin has a scalapb/package$.class that conflicts
// with the one from the scalapb runtime, so for that reason we don't produce
// unidoc for the codegen projects:
ScalaUnidoc / unidoc / unidocProjectFilter := inProjects(runtime),
// https://github.com/sbt/sbt/issues/3465
// Libs and plugins must share a version. The root project must use that
// version (and set the crossScalaVersions as empty list) so each sub-project
// can then decide which scalaVersion and crossCalaVersions they use.
crossScalaVersions := Nil,
scalaVersion := scala212)
.enablePlugins(NoPublish)
Global / onLoad := (Global / onLoad).value.andThen { s =>
val v = version.value
val log = sLog.value
log.info(
s"Building Pekko gRPC $v against Pekko ${Dependencies.Versions.pekko} and Pekko HTTP ${Dependencies.Versions.pekkoHttp}")
s
}