build.sbt (410 lines of code) (raw):
import ReleaseTransformations.*
import sbtversionpolicy.withsbtrelease.ReleaseVersion
import play.sbt.PlayImport.specs2
import sbt.Keys.{libraryDependencies, mainClass}
import sbtassembly.AssemblyPlugin.autoImport.{assemblyJarName, assemblyMergeStrategy}
import sbtassembly.MergeStrategy
import com.typesafe.sbt.packager.docker.{Cmd, ExecCmd}
val projectVersion = "1.0-latest"
ThisBuild / publish / skip := true
releaseVersion := ReleaseVersion.fromAggregatedAssessedCompatibilityWithLatestRelease().value
releaseCrossBuild := true // true if you cross-build the project for multiple Scala versions
releaseProcess := Seq[ReleaseStep](
checkSnapshotDependencies,
inquireVersions,
runClean,
runTest,
setReleaseVersion,
commitReleaseVersion,
tagRelease,
setNextVersion,
commitNextVersion
)
ThisBuild / scalaVersion := "2.13.16"
val compilerOptions = Seq(
"-deprecation",
"-Xfatal-warnings",
"-feature",
"-language:postfixOps",
"-language:implicitConversions",
"-release:11"
)
ThisBuild / scalacOptions ++= compilerOptions
val playJsonVersion = "3.0.4"
val specsVersion: String = "4.8.3"
val awsSdkVersion: String = "1.12.782"
val doobieVersion: String = "0.13.4"
val catsVersion: String = "2.13.0"
val okHttpVersion: String = "4.12.0"
val paClientVersion: String = "7.0.12"
val apacheThrift: String = "0.15.0"
val jacksonDatabind: String = "2.18.3"
val jacksonCbor: String = "2.18.3"
val jacksonScalaModule: String = "2.18.3"
val simpleConfigurationVersion: String = "1.5.7"
val googleOAuthClient: String = "1.39.0"
val nettyVersion: String = "4.1.119.Final"
val slf4jVersion: String = "1.7.36"
val logbackVersion: String = "1.5.18"
val standardSettings = Seq[Setting[_]](
// We should remove this when all transitive dependencies use the same version of scala-xml
// For now this isn't considered an issue due to the compatability between 1.2.x and 2.1.x of the library
libraryDependencySchemes += "org.scala-lang.modules" %% "scala-xml" % VersionScheme.Always,
resolvers ++= Seq(
"Guardian GitHub Releases" at "https://guardian.github.com/maven/repo-releases",
"Guardian GitHub Snapshots" at "https://guardian.github.com/maven/repo-snapshots"
),
libraryDependencies ++= Seq(
"com.github.nscala-time" %% "nscala-time" % "3.0.0",
"com.softwaremill.macwire" %% "macros" % "2.6.6" % "provided",
specs2 % Test,
"org.specs2" %% "specs2-matcher-extra" % specsVersion % Test
),
// Workaround Mockito causes deadlock on SBT classloaders: https://github.com/sbt/sbt/issues/3022
Test / parallelExecution := false,
Test / testOptions += Tests.Argument(TestFrameworks.Specs2, "junitxml", "console")
)
lazy val commoneventconsumer = project
.settings(Seq(
libraryDependencies ++= Seq(
"org.slf4j" % "slf4j-api" % slf4jVersion,
"com.amazonaws" % "aws-java-sdk-athena" % awsSdkVersion,
"org.playframework" %% "play-json" % playJsonVersion,
"org.specs2" %% "specs2-core" % specsVersion % "test",
"com.fasterxml.jackson.core" % "jackson-databind" % jacksonDatabind,
"com.fasterxml.jackson.dataformat" % "jackson-dataformat-cbor" % jacksonCbor,
"com.fasterxml.jackson.module" % "jackson-module-scala_2.13" % jacksonScalaModule
),
))
lazy val commontest = project
.settings(Seq(
libraryDependencies ++= Seq(
specs2,
playCore,
"com.fasterxml.jackson.core" % "jackson-databind" % jacksonDatabind,
"com.fasterxml.jackson.dataformat" % "jackson-dataformat-cbor" % jacksonCbor,
"com.fasterxml.jackson.module" % "jackson-module-scala_2.13" % jacksonScalaModule
),
))
lazy val common = project
.dependsOn(commoneventconsumer)
.settings(LocalDynamoDBCommon.settings)
.settings(standardSettings: _*)
.settings(
libraryDependencies ++= Seq(
ws,
"org.typelevel" %% "cats-core" % catsVersion,
"joda-time" % "joda-time" % "2.14.0",
"org.playframework" %% "play-json" % playJsonVersion,
"org.playframework" %% "play-json-joda" % playJsonVersion,
"com.gu" %% "pa-client" % paClientVersion,
"com.amazonaws" % "aws-java-sdk-dynamodb" % awsSdkVersion,
"com.amazonaws" % "aws-java-sdk-cloudwatch" % awsSdkVersion,
"com.googlecode.concurrentlinkedhashmap" % "concurrentlinkedhashmap-lru" % "1.4.2",
"ai.x" %% "play-json-extensions" % "0.42.0",
"org.tpolecat" %% "doobie-core" % doobieVersion,
"org.tpolecat" %% "doobie-hikari" % doobieVersion,
"org.tpolecat" %% "doobie-postgres" % doobieVersion,
"org.tpolecat" %% "doobie-specs2" % doobieVersion % Test,
"org.tpolecat" %% "doobie-scalatest" % doobieVersion % Test,
"org.tpolecat" %% "doobie-h2" % doobieVersion % Test,
"com.gu" %% "mobile-logstash-encoder" % "1.1.8",
"com.gu" %% "simple-configuration-ssm" % simpleConfigurationVersion,
"io.netty" % "netty-handler" % nettyVersion,
"io.netty" % "netty-codec" % nettyVersion,
"io.netty" % "netty-codec-http" % nettyVersion,
"io.netty" % "netty-codec-http2" % nettyVersion,
"io.netty" % "netty-common" % nettyVersion,
"org.postgresql" % "postgresql" % "42.7.5",
"ch.qos.logback" % "logback-core" % logbackVersion,
"ch.qos.logback" % "logback-classic" % logbackVersion,
),
fork := true,
startDynamoDBLocal := startDynamoDBLocal.dependsOn(Test / compile).value,
Test / test := (Test / test).dependsOn(startDynamoDBLocal).value,
Test / testOnly := (Test / testOnly).dependsOn(startDynamoDBLocal).evaluated,
Test / testQuick := (Test / testQuick).dependsOn(startDynamoDBLocal).evaluated,
Test / testOptions += dynamoDBLocalTestCleanup.value,
// the following option is to allow tests using wsClient such as NotificationHubClientSpec
Test / testOptions += Tests.Argument(TestFrameworks.Specs2, "sequential", "true")
)
lazy val commonscheduledynamodb = project
.settings(LocalDynamoDBScheduleLambda.settings)
.settings(List(
libraryDependencies ++= List(
"com.amazonaws" % "aws-java-sdk-dynamodb" % awsSdkVersion,
"com.fasterxml.jackson.core" % "jackson-databind" % jacksonDatabind,
"com.fasterxml.jackson.dataformat" % "jackson-dataformat-cbor" % jacksonCbor,
"com.fasterxml.jackson.module" % "jackson-module-scala_2.13" % jacksonScalaModule,
specs2 % Test
),
Test / test := (Test / test).dependsOn(startDynamoDBLocal).value,
Test / testOnly := (Test / testOnly).dependsOn(startDynamoDBLocal).evaluated,
Test / testQuick := (Test / testQuick).dependsOn(startDynamoDBLocal).evaluated,
Test / testOptions += dynamoDBLocalTestCleanup.value
))
lazy val registration = project
.dependsOn(common, commontest % "test->test")
.enablePlugins(SystemdPlugin, PlayScala, JDebPackaging)
.settings(standardSettings: _*)
.settings(
fork := true,
routesImport ++= Seq(
"binders.querystringbinders._",
"binders.pathbinders._",
"models._"
),
libraryDependencies ++= Seq(
logback,
"org.tpolecat" %% "doobie-h2" % doobieVersion % Test
),
excludeDependencies ++= Seq(
// As of Play 3.0, groupId has changed to org.playframework; exclude transitive dependencies to the old artifacts
// Hopefully this workaround can be removed once play-json-extensions either updates to Play 3.0 or is merged into play-json
ExclusionRule(organization = "com.typesafe.play")
),
Debian / packageName := name.value,
version := projectVersion
)
lazy val notification = project
.dependsOn(common)
.dependsOn(commonscheduledynamodb)
.enablePlugins(SystemdPlugin, PlayScala, JDebPackaging)
.settings(standardSettings: _*)
.settings(
fork := true,
routesImport ++= Seq(
"binders.querystringbinders._",
"binders.pathbinders._",
"models._"
),
libraryDependencies ++= Seq(
logback,
"com.amazonaws" % "aws-java-sdk-sqs" % awsSdkVersion
),
excludeDependencies ++= Seq(
// As of Play 3.0, groupId has changed to org.playframework; exclude transitive dependencies to the old artifacts
// Hopefully this workaround can be removed once play-json-extensions either updates to Play 3.0 or is merged into play-json
ExclusionRule(organization = "com.typesafe.play")
),
Debian / packageName := name.value,
version := projectVersion
)
lazy val report = project
.dependsOn(common, commontest % "test->test")
.enablePlugins(SystemdPlugin, PlayScala, JDebPackaging)
.settings(standardSettings: _*)
.settings(
fork := true,
routesImport ++= Seq(
"binders.querystringbinders._",
"binders.pathbinders._",
"org.joda.time.DateTime",
"models._"
),
libraryDependencies ++= Seq(
logback
),
excludeDependencies ++= Seq(
// As of Play 3.0, groupId has changed to org.playframework; exclude transitive dependencies to the old artifacts
// Hopefully this workaround can be removed once play-json-extensions either updates to Play 3.0 or is merged into play-json
ExclusionRule(organization = "com.typesafe.play")
),
Debian / packageName := name.value,
version := projectVersion
)
lazy val apiModels = {
import sbt.Keys.organization
import sbtrelease._
import ReleaseStateTransformations._
Project("api-models", file("api-models")).settings(Seq(
name := "mobile-notifications-api-models",
publish / skip := false,
libraryDependencies ++= Seq(
"org.playframework" %% "play-json" % playJsonVersion,
"org.specs2" %% "specs2-core" % specsVersion % "test",
"org.specs2" %% "specs2-mock" % specsVersion % "test",
"com.fasterxml.jackson.core" % "jackson-databind" % jacksonDatabind,
"com.fasterxml.jackson.dataformat" % "jackson-dataformat-cbor" % jacksonCbor,
"com.fasterxml.jackson.module" % "jackson-module-scala_2.13" % jacksonScalaModule
),
organization := "com.gu",
description := "Scala models for the Guardian Push Notifications API",
licenses := Seq(License.Apache2),
))
}
def lambda(projectName: String, directoryName: String, mainClassName: Option[String] = None): Project =
Project(projectName, file(directoryName))
.enablePlugins(AssemblyPlugin)
.settings(
organization := "com.gu",
resolvers ++= Seq(
"Guardian GitHub Releases" at "https://guardian.github.com/maven/repo-releases",
"snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"
),
libraryDependencies ++= Seq(
"com.amazonaws" % "aws-lambda-java-core" % "1.2.3",
"org.slf4j" % "slf4j-api" % slf4jVersion,
"com.gu" %% "simple-configuration-core" % simpleConfigurationVersion,
"com.gu" %% "simple-configuration-ssm" % simpleConfigurationVersion,
"ch.qos.logback" % "logback-classic" % logbackVersion,
"net.logstash.logback" % "logstash-logback-encoder" % "8.0",
specs2 % Test
),
assemblyJarName := s"$projectName.jar",
assembly / assemblyMergeStrategy := {
case "META-INF/MANIFEST.MF" => MergeStrategy.discard
case _ => MergeStrategy.first
},
Test / run / fork := true,
scalacOptions := compilerOptions,
mainClass := mainClassName,
// Workaround Mockito causes deadlock on SBT classloaders: https://github.com/sbt/sbt/issues/3022
Test / parallelExecution := false
)
lazy val schedulelambda = lambda("schedule", "schedulelambda")
.dependsOn(commonscheduledynamodb)
.settings {
List(
libraryDependencies ++= Seq(
"com.amazonaws" % "aws-java-sdk-cloudwatch" % awsSdkVersion,
"com.amazonaws" % "aws-java-sdk-dynamodb" % awsSdkVersion,
"com.squareup.okhttp3" % "okhttp" % okHttpVersion,
"org.specs2" %% "specs2-core" % specsVersion % "test",
"org.specs2" %% "specs2-scalacheck" % specsVersion % "test",
"org.specs2" %% "specs2-mock" % specsVersion % "test",
"io.netty" % "netty-common" % nettyVersion,
"io.netty" % "netty-codec" % nettyVersion,
"io.netty" % "netty-codec-http" % nettyVersion,
"io.netty" % "netty-codec-http2" % nettyVersion
),
excludeDependencies ++= Seq(
ExclusionRule("org.playframework", "play-ahc-ws_2.13"),
// As of Play 3.0, groupId has changed to org.playframework; exclude transitive dependencies to the old artifacts
// Hopefully this workaround can be removed once play-json-extensions either updates to Play 3.0 or is merged into play-json
ExclusionRule(organization = "com.typesafe.play")
),
)
}
lazy val football = lambda("football", "football")
.dependsOn(apiModels % "test->test", apiModels % "compile->compile")
.settings(
resolvers += "Guardian GitHub Releases" at "https://guardian.github.com/maven/repo-releases",
libraryDependencies ++= Seq(
"org.scanamo" %% "scanamo" % "1.0.0-M12-1",
"org.scanamo" %% "scanamo-testkit" % "1.0.0-M12-1" % "test",
"com.gu" %% "content-api-client-default" % "34.1.0",
"com.amazonaws" % "aws-java-sdk-dynamodb" % awsSdkVersion,
"com.gu" %% "pa-client" % paClientVersion,
"com.squareup.okhttp3" % "okhttp" % okHttpVersion,
"org.specs2" %% "specs2-core" % specsVersion % "test",
"org.specs2" %% "specs2-mock" % specsVersion % "test",
"io.netty" % "netty-codec" % nettyVersion,
"io.netty" % "netty-codec-http" % nettyVersion,
"io.netty" % "netty-codec-http2" % nettyVersion,
"io.netty" % "netty-common" % nettyVersion,
),
excludeDependencies ++= Seq(
ExclusionRule("org.playframework", "play-ahc-ws_2.13"),
ExclusionRule("software.amazon.awssdk", "ec2"),
// As of Play 3.0, groupId has changed to org.playframework; exclude transitive dependencies to the old artifacts
// Hopefully this workaround can be removed once play-json-extensions either updates to Play 3.0 or is merged into play-json
ExclusionRule(organization = "com.typesafe.play")
),
)
lazy val eventconsumer = lambda("eventconsumer", "eventconsumer", Some("com.gu.notifications.events.LocalRun"))
.dependsOn(commoneventconsumer)
.settings({
Seq(
description := "Consumes events produced when an app receives a notification",
libraryDependencies ++= Seq(
"org.playframework" %% "play-json" % playJsonVersion,
"com.amazonaws" % "aws-java-sdk-dynamodb" % awsSdkVersion,
"org.scala-lang.modules" %% "scala-java8-compat" % "1.0.2",
"io.netty" % "netty-codec-http2" % nettyVersion
),
)
})
lazy val sloMonitor = lambda("slomonitor", "slomonitor", Some("com.gu.notifications.slos.SloMonitor"))
.dependsOn(commoneventconsumer)
.settings({
Seq(
description := "Monitors SLO performance for breaking news notifications",
libraryDependencies ++= Seq(
"com.amazonaws" % "aws-lambda-java-events" % "3.15.0",
"com.amazonaws" % "aws-java-sdk-cloudwatch" % awsSdkVersion,
"io.netty" % "netty-codec" % nettyVersion,
"io.netty" % "netty-codec-http" % nettyVersion,
"io.netty" % "netty-codec-http2" % nettyVersion,
),
Test / fork := true,
Test / envVars := Map("STAGE" -> "TEST")
)
})
lazy val latestVersionOfLambdaSDK = {
import scala.jdk.CollectionConverters._
import com.github.dockerjava.core.DefaultDockerClientConfig
import com.github.dockerjava.httpclient5.ApacheDockerHttpClient
import com.github.dockerjava.core.DockerClientImpl
val imageName = "public.ecr.aws/lambda/java:latest"
val dockerCfg = DefaultDockerClientConfig.createDefaultConfigBuilder().build()
val dockerHttp = new ApacheDockerHttpClient.Builder()
.dockerHost(dockerCfg.getDockerHost())
.sslConfig(dockerCfg.getSSLConfig())
.build();
val docker = DockerClientImpl.getInstance(dockerCfg, dockerHttp)
docker.pullImageCmd(imageName).start().awaitCompletion()
val image = docker.inspectImageCmd(imageName).exec()
image.getRepoDigests().asScala.head
}
lazy val lambdaDockerCommands = dockerCommands := Seq(
Cmd ( "FROM", latestVersionOfLambdaSDK),
Cmd ( "LABEL", s"sdkBaseVersion=${latestVersionOfLambdaSDK}"),
ExecCmd( "COPY", "1/opt/docker/*", "${LAMBDA_TASK_ROOT}/lib/"),
ExecCmd( "COPY", "2/opt/docker/*", "${LAMBDA_TASK_ROOT}/lib/"),
Cmd ( "EXPOSE", "8080"), // this is the local lambda run time for testing
ExecCmd( "CMD", "com.gu.notifications.worker.ContainerLambdaTest::handleRequest"),
)
lazy val buildNumber = sys.env.get("BUILD_NUMBER").orElse(Some("DEV"))
lazy val ecrRepositorySettings =
sys.env.get("NOTIFICATION_LAMBDA_REPOSITORY_URL") match {
case Some(url) =>
val Array(repo, name) = url.split("/", 2)
Seq(
dockerRepository := Some(repo),
Docker / packageName := name
)
case None => Nil
}
lazy val notificationworkerlambda = lambda("notificationworkerlambda", "notificationworkerlambda", Some("com.gu.notifications.worker.TopicCounterLocalRun"))
.dependsOn(common)
.enablePlugins(DockerPlugin)
.enablePlugins(JavaAppPackaging)
.settings(ecrRepositorySettings: _*)
.settings(
lambdaDockerCommands,
dockerExposedPorts := Seq(9000), // exposed by the lambda runtime api inside the image
dockerAlias := DockerAlias(registryHost = dockerRepository.value, username = None, name = (Docker / packageName).value, tag = buildNumber),
libraryDependencies ++= Seq(
"com.turo" % "pushy" % "0.13.10",
"com.google.firebase" % "firebase-admin" % "9.2.0",
"com.google.protobuf" % "protobuf-java" % "4.30.2",
"com.google.protobuf" % "protobuf-java-util" % "4.30.2",
"com.amazonaws" % "aws-lambda-java-events" % "2.2.9",
"com.amazonaws" % "aws-java-sdk-sqs" % awsSdkVersion,
"com.amazonaws" % "aws-java-sdk-s3" % awsSdkVersion,
"com.amazonaws" % "amazon-sqs-java-messaging-lib" % "2.1.4",
"com.squareup.okhttp3" % "okhttp" % okHttpVersion,
"org.playframework" %% "play-json" % playJsonVersion,
"com.google.oauth-client" % "google-oauth-client" % googleOAuthClient,
),
excludeDependencies ++= Seq(
ExclusionRule("org.playframework", "play-ahc-ws_2.13"),
// As of Play 3.0, groupId has changed to org.playframework; exclude transitive dependencies to the old artifacts
// Hopefully this workaround can be removed once play-json-extensions either updates to Play 3.0 or is merged into play-json
ExclusionRule(organization = "com.typesafe.play")
),
)
lazy val fakebreakingnewslambda = lambda("fakebreakingnewslambda", "fakebreakingnewslambda", Some("fakebreakingnews.LocalRun"))
.dependsOn(common)
.dependsOn(apiModels % "test->test", apiModels % "compile->compile")
.settings(
libraryDependencies ++= Seq(
"com.squareup.okhttp3" % "okhttp" % okHttpVersion,
),
excludeDependencies ++= Seq(
ExclusionRule("org.playframework", "play-ahc-ws_2.13"),
// As of Play 3.0, groupId has changed to org.playframework; exclude transitive dependencies to the old artifacts
// Hopefully this workaround can be removed once play-json-extensions either updates to Play 3.0 or is merged into play-json
ExclusionRule(organization = "com.typesafe.play")
),
)
lazy val reportExtractor = lambda("reportextractor", "reportextractor", Some("com.gu.notifications.extractor.LocalRun"))
.dependsOn(common)
.settings(
excludeDependencies ++= Seq(
ExclusionRule("org.playframework", "play-ahc-ws_2.13"),
// As of Play 3.0, groupId has changed to org.playframework; exclude transitive dependencies to the old artifacts
// Hopefully this workaround can be removed once play-json-extensions either updates to Play 3.0 or is merged into play-json
ExclusionRule(organization = "com.typesafe.play")
)
)