build.sbt (403 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, which was derived from Akka.
*/
import ValidatePullRequest._
import net.bzzt.reproduciblebuilds.ReproducibleBuildsPlugin.reproducibleBuildsCheckResolver
import PekkoDependency._
import Dependencies.{ h2specExe, h2specName }
import MultiJvmPlugin.MultiJvmKeys.MultiJvm
import java.nio.file.Files
import java.nio.file.attribute.{ PosixFileAttributeView, PosixFilePermission }
import sbtdynver.GitDescribeOutput
import spray.boilerplate.BoilerplatePlugin
import com.lightbend.paradox.apidoc.ApidocPlugin.autoImport.apidocRootPackage
sourceDistName := "apache-pekko-http"
sourceDistIncubating := true
commands := commands.value.filterNot { command =>
command.nameOption.exists { name =>
name.contains("sonatypeRelease") || name.contains("sonatypeBundleRelease")
}
}
ThisBuild / reproducibleBuildsCheckResolver :=
"Apache Pekko Staging".at("https://repository.apache.org/content/groups/staging/")
addCommandAlias("verifyCodeStyle", "scalafmtCheckAll; scalafmtSbtCheck; +headerCheckAll; javafmtCheckAll")
addCommandAlias("applyCodeStyle", "+headerCreateAll; scalafmtAll; scalafmtSbt; javafmtAll")
inThisBuild(Def.settings(
apiURL := {
val apiVersion = if (isSnapshot.value) "current" else version.value
Some(url(s"https://pekko.apache.org/api/pekko-http/$apiVersion/"))
},
scmInfo := Some(
ScmInfo(url("https://github.com/apache/incubator-pekko-http"), "git@github.com:apache/incubator-pekko-http.git")),
description := "Apache Pekko Http: Modern, fast, asynchronous, streaming-first HTTP server and client.",
testOptions ++= Seq(
Tests.Argument(TestFrameworks.JUnit, "-q", "-v"),
Tests.Argument(TestFrameworks.ScalaTest, "-oDF")),
Dependencies.Versions,
shellPrompt := { s => Project.extract(s).currentProject.id + " > " },
concurrentRestrictions in Global += Tags.limit(Tags.Test, 1),
onLoad in Global := {
sLog.value.info(
s"Building Pekko HTTP ${version.value} against Pekko ${PekkoDependency.pekkoVersion} on Scala ${(httpCore / scalaVersion).value}")
(onLoad in Global).value
},
projectInfoVersion := (if (isSnapshot.value) "snapshot" else version.value),
scalafixScalaBinaryVersion := scalaBinaryVersion.value,
apacheSonatypeProjectProfile := "pekko",
versionScheme := Some(VersionScheme.SemVerSpec)))
// When this is updated the set of modules in Http.allModules should also be updated
lazy val userProjects: Seq[ProjectReference] = List[ProjectReference](
parsing,
httpCore,
http2Tests,
http,
httpCaching,
httpCors,
httpTestkit,
httpMarshallersScala,
httpMarshallersJava,
httpSprayJson,
httpXml,
httpJackson,
httpScalafixRules // don't aggregate tests for now as this will break with Scala compiler updates too easily
)
lazy val aggregatedProjects: Seq[ProjectReference] = userProjects ++ List[ProjectReference](
httpTests,
docs,
// compatibilityTests,
httpJmhBench,
billOfMaterials)
lazy val root = Project(
id = "pekko-http",
base = file("."))
.enablePlugins(UnidocRoot, NoPublish, AggregatePRValidation, NoScala3)
.disablePlugins(MimaPlugin)
.settings(
name := "pekko-http-root",
// Unidoc doesn't like macro definitions
// compatibilityTests temporarily disabled
unidocProjectExcludes := Seq(parsing, docs, httpTests, httpJmhBench, httpScalafix, httpScalafixRules,
httpScalafixTestInput, httpScalafixTestOutput, httpScalafixTests),
// Support applying macros in unidoc:
scalaMacroSupport,
Compile / headerCreate / unmanagedSources := (baseDirectory.value / "project").**("*.scala").get)
.aggregate(aggregatedProjects: _*)
/**
* Adds a `src/.../scala-2.13+` source directory for Scala 2.13 and newer
* and a `src/.../scala-2.13-` source directory for Scala version older than 2.13
*/
def add213CrossDirs(config: Configuration): Seq[Setting[_]] = Seq(
config / unmanagedSourceDirectories += {
val sourceDir = (config / sourceDirectory).value
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((e, n)) if e > 2 || (e == 2 && n >= 13) => sourceDir / "scala-2.13+"
case _ => sourceDir / "scala-2.13-"
}
})
val commonSettings =
add213CrossDirs(Compile) ++
add213CrossDirs(Test)
val scalaMacroSupport = Seq(
scalacOptions ++= {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, n)) if n >= 13 =>
Seq("-Ymacro-annotations")
case _ =>
Seq.empty
}
},
libraryDependencies ++= (CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, n)) if n < 13 =>
Seq(compilerPlugin(("org.scalamacros" % "paradise" % "2.1.1").cross(CrossVersion.full)))
case _ => Seq.empty
}))
lazy val parsing = project("parsing")
.settings(commonSettings)
.settings(AutomaticModuleName.settings("pekko.http.parsing"))
.addPekkoModuleDependency("pekko-actor", "provided")
.settings(Dependencies.parsing)
.settings(scalacOptions += "-language:_")
.settings(scalaMacroSupport)
.enablePlugins(ScaladocNoVerificationOfDiagrams)
.enablePlugins(ReproducibleBuildsPlugin)
.disablePlugins(MimaPlugin)
lazy val httpCore = project("http-core")
.settings(commonSettings)
.settings(AutomaticModuleName.settings("pekko.http.core"))
.settings(AddMetaInfLicenseFiles.httpCoreSettings)
.dependsOn(parsing /*, httpScalafixRules % ScalafixConfig*/ )
.addPekkoModuleDependency("pekko-stream", "provided")
.addPekkoModuleDependency(
"pekko-stream-testkit",
"test",
pekko =
if (System.getProperty("pekko.http.test-against-pekko-main", "false") == "true") PekkoDependency.mainSnapshot
else PekkoDependency.default)
.settings(Dependencies.httpCore)
.settings(VersionGenerator.versionSettings)
.settings(scalaMacroSupport)
.enablePlugins(BootstrapGenjavadoc)
.enablePlugins(ReproducibleBuildsPlugin)
.enablePlugins(Pre213Preprocessor).settings(
Pre213Preprocessor.pre213Files := Seq(
"headers.scala", "HttpMessage.scala", "LanguageRange.scala", "CacheDirective.scala", "LinkValue.scala"))
.disablePlugins(ScalafixPlugin)
lazy val http = project("http")
.settings(commonSettings)
.settings(AutomaticModuleName.settings("pekko.http"))
.dependsOn(httpCore)
.addPekkoModuleDependency("pekko-stream", "provided")
.settings(Dependencies.http)
.settings(
Compile / scalacOptions += "-language:_")
.settings(scalaMacroSupport)
.enablePlugins(Pre213Preprocessor).settings(
Pre213Preprocessor.pre213Files := Seq(
"scaladsl/server/directives/FormFieldDirectives.scala", "scaladsl/server/directives/RespondWithDirectives.scala"))
.enablePlugins(BootstrapGenjavadoc, BoilerplatePlugin)
.enablePlugins(ReproducibleBuildsPlugin)
lazy val http2Tests = project("http2-tests")
.settings(commonSettings)
.settings(AutomaticModuleName.settings("pekko.http.http2"))
.dependsOn(httpCore, httpTestkit % "test", httpCore % "test->test")
.addPekkoModuleDependency("pekko-stream", "provided")
.addPekkoModuleDependency("pekko-stream-testkit", "test")
.settings(Dependencies.http2Tests)
.settings {
lazy val h2specPath = Def.task {
(Test / target).value / h2specName / h2specExe
}
Seq(
Test / run / fork := true,
Test / fork := true,
Test / run / sbt.Keys.connectInput := true,
Test / javaOptions += "-Dh2spec.path=" + h2specPath.value,
Test / resourceGenerators += Def.task {
val log = streams.value.log
val h2spec = h2specPath.value
if (!h2spec.exists) {
log.info("Extracting h2spec to " + h2spec)
for (zip <- (Test / update).value.select(artifact = artifactFilter(name = h2specName, extension = "zip")))
IO.unzip(zip, (Test / target).value / h2specName)
for (tarGz <- (Test / update).value.select(artifact = artifactFilter(name = h2specName, extension = "gz")))
Untar.unTarGz(tarGz, (Test / target).value / h2specName)
// Set the executable bit on the expected path to fail if it doesn't exist
for (view <- Option(Files.getFileAttributeView(h2spec.toPath, classOf[PosixFileAttributeView]))) {
val permissions = view.readAttributes.permissions
if (permissions.add(PosixFilePermission.OWNER_EXECUTE))
view.setPermissions(permissions)
}
}
Seq(h2spec)
})
}
.enablePlugins(NoPublish) // only contains tests these days
.disablePlugins(MimaPlugin) // experimental module still
lazy val httpTestkit = project("http-testkit")
.settings(commonSettings)
.settings(AutomaticModuleName.settings("pekko.http.testkit"))
.dependsOn(http)
.addPekkoModuleDependency("pekko-stream-testkit", "provided")
.addPekkoModuleDependency("pekko-testkit", "provided")
.settings(Dependencies.httpTestkit)
.settings(
// don't ignore Suites which is the default for the junit-interface
testOptions += Tests.Argument(TestFrameworks.JUnit, "--ignore-runners="),
Compile / scalacOptions ++= Seq("-language:_"),
Test / run / mainClass := Some("org.apache.pekko.http.javadsl.SimpleServerApp"))
.enablePlugins(BootstrapGenjavadoc, MultiNodeScalaTest, ScaladocNoVerificationOfDiagrams)
.enablePlugins(ReproducibleBuildsPlugin)
.disablePlugins(MimaPlugin) // testkit, no bin compat guaranteed
lazy val httpTests = project("http-tests")
.settings(commonSettings)
.settings(Dependencies.httpTests)
.dependsOn(httpSprayJson, httpXml, httpJackson,
httpTestkit % "test", httpCore % "test->test",
httpScalafixRules % ScalafixConfig)
.enablePlugins(NoPublish) // don't release tests
.enablePlugins(MultiNode)
.disablePlugins(MimaPlugin) // this is only tests
.configs(MultiJvm)
.settings(headerSettings(MultiJvm))
.addPekkoModuleDependency("pekko-stream", "provided")
.addPekkoModuleDependency("pekko-multi-node-testkit", "test")
.settings(
// Fix to reenable scala-steward, see https://gitter.im/scala-steward-org/scala-steward?at=6183bb66d78911028a1b7cd8
// Putting that jar file with the complicated name into the git tree directly breaks if something in the environment
// has unicode path names configured wrongly. So, we wrap it into an extra zip file which is extracted before
// tests are run.
Test / unmanagedJars += {
val targetDir = target.value / "extra-libs"
val targetFile = targetDir / "i have späces.jar"
if (!targetFile.exists) {
val zipFile = (Test / sourceDirectory).value / "extra-libs.zip"
IO.unzip(zipFile, targetDir)
}
targetFile
})
lazy val httpJmhBench = project("http-bench-jmh")
.settings(commonSettings)
.dependsOn(http, httpCors, http2Tests % "compile->compile,test")
.addPekkoModuleDependency("pekko-stream")
.enablePlugins(JmhPlugin)
.enablePlugins(NoPublish) // don't release benchs
.disablePlugins(MimaPlugin)
lazy val httpMarshallersScala = project("http-marshallers-scala")
.settings(commonSettings)
.enablePlugins(NoPublish /*, AggregatePRValidation*/ )
.disablePlugins(MimaPlugin)
.aggregate(httpSprayJson, httpXml)
lazy val httpXml =
httpMarshallersScalaSubproject("xml")
.settings(AutomaticModuleName.settings("pekko.http.marshallers.scalaxml"))
.addPekkoModuleDependency("pekko-stream", "provided")
.settings(Dependencies.httpXml)
lazy val httpSprayJson =
httpMarshallersScalaSubproject("spray-json")
.settings(AutomaticModuleName.settings("pekko.http.marshallers.sprayjson"))
.addPekkoModuleDependency("pekko-stream", "provided")
.settings(Dependencies.httpSprayJson)
lazy val httpMarshallersJava = project("http-marshallers-java")
.settings(commonSettings)
.enablePlugins(NoPublish /*, AggregatePRValidation*/ )
.disablePlugins(MimaPlugin)
.aggregate(httpJackson)
lazy val httpJackson =
httpMarshallersJavaSubproject("jackson")
.settings(AutomaticModuleName.settings("pekko.http.marshallers.jackson"))
.addPekkoModuleDependency("pekko-stream", "provided")
.addPekkoModuleDependency("pekko-stream-testkit", "test")
.dependsOn(httpTestkit % "test")
.settings(Dependencies.httpJackson)
.enablePlugins(ScaladocNoVerificationOfDiagrams)
lazy val httpCaching = project("http-caching")
.settings(
name := "pekko-http-caching")
.settings(commonSettings)
.settings(AutomaticModuleName.settings("pekko.http.caching"))
.addPekkoModuleDependency("pekko-stream", "provided")
.addPekkoModuleDependency("pekko-stream-testkit", "provided")
.settings(Dependencies.httpCaching)
.dependsOn(http, httpCore, httpTestkit % "test")
.enablePlugins(BootstrapGenjavadoc)
lazy val httpCors = project("http-cors")
.settings(
name := "pekko-http-cors")
.settings(commonSettings)
.settings(AutomaticModuleName.settings("pekko.http.cors"))
.settings(AddMetaInfLicenseFiles.httpCorsSettings)
.addPekkoModuleDependency("pekko-stream", "provided")
.addPekkoModuleDependency("pekko-stream-testkit", "provided")
.settings(Dependencies.httpCors)
.dependsOn(http, httpCore, httpTestkit % "test")
.enablePlugins(BootstrapGenjavadoc)
def project(moduleName: String) =
Project(id = moduleName, base = file(moduleName)).settings(
name := s"pekko-$moduleName")
def httpMarshallersScalaSubproject(moduleName: String) =
Project(
id = s"http-$moduleName",
base = file(s"http-marshallers-scala/http-$moduleName"))
.dependsOn(http)
.settings(
name := s"pekko-http-$moduleName")
.settings(commonSettings)
.enablePlugins(BootstrapGenjavadoc)
.enablePlugins(ReproducibleBuildsPlugin)
def httpMarshallersJavaSubproject(moduleName: String) =
Project(
id = s"http-$moduleName",
base = file(s"http-marshallers-java/http-$moduleName"))
.settings(
name := s"pekko-http-$moduleName")
.dependsOn(http)
.settings(commonSettings)
.enablePlugins(BootstrapGenjavadoc)
.enablePlugins(ReproducibleBuildsPlugin)
lazy val httpScalafix = project("http-scalafix")
.enablePlugins(NoPublish, NoScala3)
.disablePlugins(MimaPlugin)
.aggregate(httpScalafixRules, httpScalafixTestInput, httpScalafixTestOutput, httpScalafixTests)
lazy val httpScalafixRules =
Project(id = "http-scalafix-rules", base = file("http-scalafix/scalafix-rules"))
.settings(
name := "pekko-http-scalafix-rules",
libraryDependencies += Dependencies.Compile.scalafix)
.enablePlugins(NoScala3)
.disablePlugins(MimaPlugin) // tooling, no bin compat guaranteed
lazy val httpScalafixTestInput =
Project(id = "http-scalafix-test-input", base = file("http-scalafix/scalafix-test-input"))
.dependsOn(http)
.addPekkoModuleDependency("pekko-stream")
.enablePlugins(NoPublish, NoScala3)
.disablePlugins(MimaPlugin, HeaderPlugin /* because it gets confused about metaheader required for tests */ )
.settings(
addCompilerPlugin(scalafixSemanticdb),
scalacOptions ++= List(
"-Yrangepos",
"-P:semanticdb:synthetics:on"),
scalacOptions := scalacOptions.value.filterNot(Set("-deprecation", "-Xlint").contains(_)) // we expect deprecated stuff in there
)
lazy val httpScalafixTestOutput =
Project(id = "http-scalafix-test-output", base = file("http-scalafix/scalafix-test-output"))
.dependsOn(http)
.addPekkoModuleDependency("pekko-stream")
.enablePlugins(NoPublish, NoScala3)
.disablePlugins(MimaPlugin, HeaderPlugin /* because it gets confused about metaheader required for tests */ )
lazy val httpScalafixTests =
Project(id = "http-scalafix-tests", base = file("http-scalafix/scalafix-tests"))
.enablePlugins(NoPublish, NoScala3)
.disablePlugins(MimaPlugin)
.settings(
name := "pekko-http-scalafix-tests",
publish / skip := true,
libraryDependencies += ("ch.epfl.scala" % "scalafix-testkit" % Dependencies.scalafixVersion % Test).cross(
CrossVersion.full),
Compile / compile :=
(Compile / compile).dependsOn(httpScalafixTestInput / Compile / compile).value,
scalafixTestkitOutputSourceDirectories :=
(httpScalafixTestOutput / Compile / sourceDirectories).value,
scalafixTestkitInputSourceDirectories :=
(httpScalafixTestInput / Compile / sourceDirectories).value,
scalafixTestkitInputClasspath :=
(httpScalafixTestInput / Compile / fullClasspath).value)
.dependsOn(httpScalafixRules)
.enablePlugins(ScalafixTestkitPlugin)
lazy val docs = project("docs")
.enablePlugins(ParadoxPlugin, PekkoParadoxPlugin, NoPublish)
.disablePlugins(MimaPlugin)
.addPekkoModuleDependency("pekko-stream", "provided", PekkoDependency.docs)
.addPekkoModuleDependency("pekko-actor-typed", "provided", PekkoDependency.docs)
.addPekkoModuleDependency("pekko-multi-node-testkit", "provided", PekkoDependency.docs)
.addPekkoModuleDependency("pekko-stream-testkit", "provided", PekkoDependency.docs)
.addPekkoModuleDependency("pekko-actor-testkit-typed", "provided", PekkoDependency.docs)
.dependsOn(
httpCore, http, httpXml, http2Tests, httpMarshallersJava, httpMarshallersScala, httpCaching, httpCors,
httpTests % "compile;test->test", httpTestkit % "compile;test->test", httpScalafixRules % ScalafixConfig)
.settings(Dependencies.docs)
.settings(
name := "pekko-http-docs",
resolvers += Resolver.jcenterRepo,
scalacOptions ++= Seq(
// Make sure we don't accidentally keep documenting deprecated calls
"-Xfatal-warnings",
// Does not appear to lead to problems
"-Wconf:msg=The outer reference in this type test cannot be checked at run time:s"),
scalacOptions ++= (
if (scalaVersion.value.startsWith("3")) Seq.empty
else Seq(
// In docs adding an unused variable can be helpful, for example
// to show its type
"-Xlint:-unused")
),
scalacOptions --= Seq(
// Code after ??? can be considered 'dead', but still useful for docs
"-Ywarn-dead-code"),
paradoxParsingTimeout := {
import scala.concurrent.duration._
10.seconds
},
paradoxGroups := Map("Language" -> Seq("Scala", "Java")),
Compile / paradoxProperties ++= Map(
"project.name" -> "Apache Pekko HTTP",
"canonical.base_url" -> "https://pekko.apache.org/docs/pekko-http/current",
"pekko.version" -> PekkoDependency.docs.version,
"jackson.xml.version" -> Dependencies.jacksonXmlVersion,
"scalafix.version" -> _root_.scalafix.sbt.BuildInfo.scalafixVersion, // grab from scalafix plugin directly
"extref.pekko-docs.base_url" -> s"https://pekko.apache.org/docs/pekko/current/%s",
"javadoc.java.base_url" -> "https://docs.oracle.com/en/java/javase/11/docs/api/java.base/",
"javadoc.java.link_style" -> "direct",
"javadoc.org.apache.pekko.base_url" -> s"https://pekko.apache.org/japi/pekko/${PekkoDependency.docs.link}",
"javadoc.org.apache.pekko.link_style" -> "direct",
"scaladoc.org.apache.pekko.base_url" -> s"https://pekko.apache.org/api/pekko/${PekkoDependency.docs.link}",
"scaladoc.org.apache.pekko.link_style" -> "direct",
"javadoc.org.apache.pekko.http.base_url" -> s"https://pekko.apache.org/api/pekko-http/${projectInfoVersion.value}",
"scaladoc.org.apache.pekko.http.base_url" -> s"https://pekko.apache.org/japi/pekko-http/${projectInfoVersion.value}",
"github.base_url" -> GitHub.url(version.value, isSnapshot.value)),
apidocRootPackage := "org.apache.pekko",
ValidatePR / additionalTasks += Compile / paradox)
.settings(ParadoxSupport.paradoxWithCustomDirectives)
/*
lazy val compatibilityTests = Project("http-compatibility-tests", file("http-compatibility-tests"))
.enablePlugins(NoPublish, NoScala3)
.disablePlugins(MimaPlugin)
.addPekkoModuleDependency("pekko-stream", "provided")
.settings(
libraryDependencies ++= Seq(
"org.apache.pekko" %% "pekko-http" % MiMa.latest101Version % "provided",
),
(Test / dependencyClasspath) := {
// HACK: We'd like to use `dependsOn(http % "test->compile")` to upgrade the explicit dependency above to the
// current version but that fails. So, this is a manual `dependsOn` which works as expected.
(Test / dependencyClasspath).value.filterNot(_.data.getName contains "pekko") ++
(httpTests / Test / fullClasspath).value
}
)
*/
lazy val billOfMaterials = Project("bill-of-materials", file("bill-of-materials"))
.enablePlugins(BillOfMaterialsPlugin)
.disablePlugins(MimaPlugin)
.settings(
name := "pekko-http-bom",
bomIncludeProjects := userProjects)
def hasCommitsAfterTag(description: Option[GitDescribeOutput]): Boolean = description.get.commitSuffix.distance > 0