diff --git a/.gitignore b/.gitignore index 899f249c..9fe670ad 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ native/ /**/*.pdf /**/.DS_Store site/ +/.sbtopts diff --git a/baas-image-builder/src/main/scala/com/ing/baker/baas/Main.scala b/baas-image-builder/src/main/scala/com/ing/baker/baas/Main.scala new file mode 100644 index 00000000..8e29e33d --- /dev/null +++ b/baas-image-builder/src/main/scala/com/ing/baker/baas/Main.scala @@ -0,0 +1,22 @@ +package com.ing.baker.baas + +import com.ing.baker.baas.scaladsl.RemoteInteraction +import com.ing.baker.runtime.scaladsl.InteractionInstance + +import scala.concurrent.ExecutionContext.Implicits.global + +/** + * Expects single argument containing full classpath entry point for interaction + */ +object Main extends App { + private def runApp(entryClassName: String): Unit = + try { + val implementation = Class.forName(entryClassName).newInstance.asInstanceOf[AnyRef] + RemoteInteraction.load(InteractionInstance.unsafeFrom(implementation)) + } catch { + case ex: Exception => + throw new IllegalStateException(s"Unable to initialize the class name $entryClassName", ex) + } + + args.headOption.map(runApp).getOrElse(throw new IllegalAccessException("Expected class name a parameter")) +} \ No newline at end of file diff --git a/baas-smoke-tests/src/test/resources/kubernetes/example-interactions.yaml b/baas-smoke-tests/src/test/resources/kubernetes/example-interactions.yaml index cd286aa8..5501f391 100644 --- a/baas-smoke-tests/src/test/resources/kubernetes/example-interactions.yaml +++ b/baas-smoke-tests/src/test/resources/kubernetes/example-interactions.yaml @@ -34,7 +34,7 @@ spec: spec: containers: - name: baas-interaction - image: baas-interaction-example-reserve-items:3.0.2-SNAPSHOT + image: interaction-webshop.webservice.reserveitemsinstance:3.0.2-SNAPSHOT imagePullPolicy: Never env: - name: BAAS_INGREDIENT_ENCRYPTION_ENABLED @@ -95,7 +95,7 @@ spec: spec: containers: - name: baas-interaction - image: baas-interaction-example-ship-items:3.0.2-SNAPSHOT + image: interaction-webshop.webservice.shipitemsinstance:3.0.2-SNAPSHOT imagePullPolicy: Never env: - name: BAAS_INGREDIENT_ENCRYPTION_ENABLED @@ -156,7 +156,7 @@ spec: spec: containers: - name: baas-interaction - image: baas-interaction-example-make-payment:3.0.2-SNAPSHOT + image: interaction-webshop.webservice.makepaymentinstance:3.0.2-SNAPSHOT imagePullPolicy: Never env: - name: BAAS_INGREDIENT_ENCRYPTION_ENABLED diff --git a/baas-smoke-tests/src/test/scala/com/ing/baker/baas/smoke/BakeryFunSpec.scala b/baas-smoke-tests/src/test/scala/com/ing/baker/baas/smoke/BakeryFunSpec.scala index 7429e8b2..b85bf959 100644 --- a/baas-smoke-tests/src/test/scala/com/ing/baker/baas/smoke/BakeryFunSpec.scala +++ b/baas-smoke-tests/src/test/scala/com/ing/baker/baas/smoke/BakeryFunSpec.scala @@ -89,7 +89,7 @@ abstract class BakeryFunSpec extends fixture.AsyncFunSpecLike { def cleanup[A](f: IO[A]): IO[Unit] = if(args.skipCleanup) IO.unit else f.void - def processLogger(prefix: String) = ProcessLogger( + def processLogger(prefix: String): ProcessLogger = ProcessLogger( line => println(prefix + " " + line), err => stderr.println(Console.RED + err + Console.RESET)) diff --git a/build.sbt b/build.sbt index 45fb1faf..0896bb02 100644 --- a/build.sbt +++ b/build.sbt @@ -3,6 +3,22 @@ import sbt.Keys._ def testScope(project: ProjectReference): ClasspathDep[ProjectReference] = project % "test->test;test->compile" +lazy val buildExampleDockerCommand: Command = Command.command("buildExampleDocker")({ + state => + val extracted = Project.extract(state) + val currentVersion = extracted.get(version in ThisBuild) + + "baas-node-state/docker:publishLocal" :: + "baas-client-example/docker:publishLocal" :: + "baas-event-listener-example/docker:publishLocal" :: + "baas-baker-event-listener-example/docker:publishLocal" :: + s"baas-interaction-example-make-payment/publishLocal; project baas-image-builder; buildInteractionDockerImage docker:publishLocal com.ing.baker:baas-interaction-example-make-payment_2.12:${currentVersion} webshop.webservice.MakePaymentInstance" :: + s"baas-interaction-example-ship-items/publishLocal; project baas-image-builder; buildInteractionDockerImage docker:publishLocal com.ing.baker:baas-interaction-example-ship-items_2.12:${currentVersion} webshop.webservice.ShipItemsInstance" :: + s"baas-interaction-example-reserve-items/publishLocal; project baas-image-builder; buildInteractionDockerImage docker:publishLocal com.ing.baker:baas-interaction-example-reserve-items_2.12:${currentVersion} webshop.webservice.ReserveItemsInstance" :: + "project baker" :: + state +}) + val commonSettings = Defaults.coreDefaultSettings ++ Seq( organization := "com.ing.baker", scalaVersion := "2.12.4", @@ -24,7 +40,7 @@ val commonSettings = Defaults.coreDefaultSettings ++ Seq( "-Xfatal-warnings" ), coverageExcludedPackages := ";.*.javadsl;.*.scaladsl;.*.common;.*.protobuf", - packageOptions in (Compile, packageBin) += + packageOptions in(Compile, packageBin) += Package.ManifestAttributes( "Build-Time" -> new java.util.Date().toString, "Build-Commit" -> git.gitHeadCommit.value.getOrElse("No Git Revision Found") @@ -61,7 +77,7 @@ lazy val bakertypes = project.in(file("bakertypes")) typeSafeConfig, scalaReflect(scalaVersion.value), scalaLogging - ) ++ testDeps(scalaTest, scalaCheck, logback, scalaCheck) + ) ++ testDeps(scalaTest, scalaCheck, scalaCheck) ) lazy val intermediateLanguage = project.in(file("intermediate-language")) @@ -74,7 +90,7 @@ lazy val intermediateLanguage = project.in(file("intermediate-language")) scalaGraphDot, typeSafeConfig, scalaLogging - ) ++ testDeps(scalaTest, scalaCheck, logback) + ) ++ testDeps(scalaTest, scalaCheck) ).dependsOn(bakertypes) lazy val `baker-interface` = project.in(file("baker-interface")) @@ -96,7 +112,7 @@ lazy val runtime = project.in(file("runtime")) .settings( moduleName := "baker-runtime", // we have to exclude the sources because of a compiler bug: https://issues.scala-lang.org/browse/SI-10134 - sources in (Compile, doc) := Seq.empty, + sources in(Compile, doc) := Seq.empty, libraryDependencies ++= compileDeps( akkaActor, @@ -129,8 +145,7 @@ lazy val runtime = project.in(file("runtime")) junitInterface, scalaTest, scalaCheck, - mockito, - logback) + mockito) ++ providedDeps(findbugs) ) .dependsOn( @@ -147,7 +162,7 @@ lazy val splitBrainResolver = project.in(file("split-brain-resolver")) .settings( moduleName := "baker-split-brain-resolver", // we have to exclude the sources because of a compiler bug: https://issues.scala-lang.org/browse/SI-10134 - sources in (Compile, doc) := Seq.empty, + sources in(Compile, doc) := Seq.empty, libraryDependencies ++= compileDeps( akkaActor, @@ -164,7 +179,7 @@ lazy val splitBrainResolver = project.in(file("split-brain-resolver")) .enablePlugins(MultiJvmPlugin) .configs(MultiJvm) .settings( -// logLevel := Level.Debug + // logLevel := Level.Debug ) lazy val recipeDsl = project.in(file("recipe-dsl")) @@ -172,7 +187,7 @@ lazy val recipeDsl = project.in(file("recipe-dsl")) .settings( moduleName := "baker-recipe-dsl", // we have to exclude the sources because of a compiler bug: https://issues.scala-lang.org/browse/SI-10134 - sources in (Compile, doc) := Seq.empty, + sources in(Compile, doc) := Seq.empty, libraryDependencies ++= compileDeps( javaxInject, @@ -183,8 +198,7 @@ lazy val recipeDsl = project.in(file("recipe-dsl")) scalaTest, scalaCheck, junitInterface, - slf4jApi, - logback + slf4jApi ) ).dependsOn(bakertypes) @@ -193,7 +207,7 @@ lazy val recipeCompiler = project.in(file("compiler")) .settings( moduleName := "baker-compiler", libraryDependencies ++= - testDeps(scalaTest, scalaCheck, logback, junitJupiter) + testDeps(scalaTest, scalaCheck, junitJupiter) ) .dependsOn(recipeDsl, intermediateLanguage, testScope(recipeDsl)) @@ -256,6 +270,16 @@ lazy val `baas-node-client` = project.in(file("baas-node-client")) ) .dependsOn(`baker-interface`, `baas-protocol-baker`) +lazy val `baas-image-builder` = project.in(file("baas-image-builder")) + .settings(defaultModuleSettings) + .settings( + moduleName := "baas-image-builder", + libraryDependencies ++= Seq( + ) + ) + .enablePlugins(baas.sbt.BuildInteractionDockerImageSBTPlugin) + .dependsOn(`baas-node-interaction`) + lazy val `baas-node-state` = project.in(file("baas-node-state")) .enablePlugins(JavaAppPackaging) .settings(commonSettings) @@ -267,7 +291,6 @@ lazy val `baas-node-state` = project.in(file("baas-node-state")) libraryDependencies ++= Seq( slf4jApi, slf4jSimple, - logback, akkaHttp, akkaPersistenceCassandra, akkaManagementHttp, @@ -277,7 +300,6 @@ lazy val `baas-node-state` = project.in(file("baas-node-state")) ) ++ testDeps( slf4jApi, slf4jSimple, - logback, scalaTest, mockServer, akkaHttpCirce, @@ -312,7 +334,6 @@ lazy val `baas-node-interaction` = project.in(file("baas-node-interaction")) slf4jApi ) ++ testDeps( akkaSlf4j, - logback, scalaTest, junitInterface, scalaCheck @@ -326,10 +347,10 @@ lazy val `baas-node-event-listener` = project.in(file("baas-node-event-listener" moduleName := "baas-node-event-listener", libraryDependencies ++= Seq( akkaHttp, + akkaCluster, slf4jApi, slf4jSimple ) ++ testDeps( - logback, scalaTest, junitInterface, scalaCheck @@ -346,7 +367,6 @@ lazy val `baas-node-baker-event-listener` = project.in(file("baas-node-baker-eve slf4jApi, slf4jSimple ) ++ testDeps( - logback, scalaTest, junitInterface, scalaCheck @@ -357,8 +377,8 @@ lazy val `baas-node-baker-event-listener` = project.in(file("baas-node-baker-eve lazy val baker = project.in(file(".")) .settings(defaultModuleSettings) .settings(noPublishSettings) - .aggregate(bakertypes, runtime, recipeCompiler, recipeDsl, intermediateLanguage, splitBrainResolver, - `baas-node-client`, `baas-node-state`, `baas-node-interaction`, `baas-node-event-listener`, `baas-node-baker-event-listener`) + .aggregate(bakertypes, runtime, recipeCompiler, recipeDsl, intermediateLanguage, splitBrainResolver, `baas-image-builder`, + `baas-node-client`, `baas-node-state`, `baas-node-interaction`, `baas-node-event-listener`, `baas-node-baker-event-listener`, `sbt-baas-docker-generate`) lazy val `baker-example` = project .in(file("examples/baker-example")) @@ -389,8 +409,7 @@ lazy val `baker-example` = project scalaCheck, junitInterface, slf4jApi, - mockito, - logback + mockito ) ) .settings( @@ -415,7 +434,6 @@ lazy val `baas-client-example` = project compileDeps( slf4jApi, slf4jSimple, - logback, http4s, http4sDsl, http4sServer, @@ -449,7 +467,6 @@ lazy val `baas-event-listener-example` = project compileDeps( slf4jApi, slf4jSimple, - logback, http4s, http4sDsl, http4sServer, @@ -477,7 +494,6 @@ lazy val `baas-baker-event-listener-example` = project compileDeps( slf4jApi, slf4jSimple, - logback, http4s, http4sDsl, http4sServer, @@ -579,6 +595,7 @@ lazy val `baas-smoke-tests` = project.in(file("baas-smoke-tests")) .settings(noPublishSettings) .settings( moduleName := "baas-smoke-tests", + commands += buildExampleDockerCommand, libraryDependencies ++= Seq() ++ testDeps( http4sDsl, @@ -586,10 +603,26 @@ lazy val `baas-smoke-tests` = project.in(file("baas-smoke-tests")) circe, slf4jApi, slf4jSimple, - logback, scalaTest, scalaCheck ) ) - .dependsOn(`baas-node-client`, `baas-client-example`) + .dependsOn( + `baas-node-client`, + `baas-client-example`, + `baas-interaction-example-make-payment`, + `baas-interaction-example-reserve-items`, + `baas-interaction-example-ship-items`) +lazy val `sbt-baas-docker-generate` = project.in(file("sbt-baas-docker-generate")) + .settings(defaultModuleSettings) + .settings( + sourceGenerators in Compile += Def.task { + val file = (sourceManaged in Compile).value / "baas" / "sbt" / "BuildInteractionDockerImageSBTPlugin.scala" + val sourceFile = IO.readBytes(baseDirectory.value.getParentFile / "project" / "BuildInteractionDockerImageSBTPlugin.scala") + IO.write(file, sourceFile) + Seq(file) + }.taskValue, + addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.6.0") + ) + .enablePlugins(SbtPlugin) \ No newline at end of file diff --git a/examples/baas-interaction-examples/make-payment/src/main/scala/webshop/webservice/Main.scala b/examples/baas-interaction-examples/make-payment/src/main/scala/webshop/webservice/Main.scala index d2291a4f..2628d58b 100644 --- a/examples/baas-interaction-examples/make-payment/src/main/scala/webshop/webservice/Main.scala +++ b/examples/baas-interaction-examples/make-payment/src/main/scala/webshop/webservice/Main.scala @@ -2,8 +2,9 @@ package webshop.webservice import com.ing.baker.baas.scaladsl.RemoteInteraction import com.ing.baker.runtime.scaladsl.InteractionInstance -import concurrent.ExecutionContext.Implicits.global + +import scala.concurrent.ExecutionContext.Implicits.global object Main extends App { - RemoteInteraction.load(InteractionInstance.unsafeFrom(new MakePaymentInstance())) + RemoteInteraction.load(InteractionInstance.unsafeFrom(new MakePaymentInstance)) } \ No newline at end of file diff --git a/examples/baas-interaction-examples/make-payment/src/main/scala/webshop/webservice/MakePaymentInstance.scala b/examples/baas-interaction-examples/make-payment/src/main/scala/webshop/webservice/MakePaymentInstance.scala index 3c80475b..4cd8b98e 100644 --- a/examples/baas-interaction-examples/make-payment/src/main/scala/webshop/webservice/MakePaymentInstance.scala +++ b/examples/baas-interaction-examples/make-payment/src/main/scala/webshop/webservice/MakePaymentInstance.scala @@ -5,9 +5,10 @@ import cats.effect.{IO, Timer} import scala.concurrent.duration._ import scala.concurrent.{ExecutionContext, Future} -class MakePaymentInstance(implicit context: ExecutionContext) extends MakePayment { +class MakePaymentInstance extends MakePayment { - implicit val timer: Timer[IO] = IO.timer(context) + private val ctx: ExecutionContext = concurrent.ExecutionContext.Implicits.global + private implicit val timer: Timer[IO] = IO.timer(ctx) override def apply(processId: String, items: ReservedItems, address: ShippingAddress, payment: PaymentInformation): Future[MakePaymentOutput] = { IO.sleep(1.second) diff --git a/examples/baas-interaction-examples/reserve-items/src/main/scala/webshop/webservice/ReserveItemsInstance.scala b/examples/baas-interaction-examples/reserve-items/src/main/scala/webshop/webservice/ReserveItemsInstance.scala index 75502dd5..713ab000 100644 --- a/examples/baas-interaction-examples/reserve-items/src/main/scala/webshop/webservice/ReserveItemsInstance.scala +++ b/examples/baas-interaction-examples/reserve-items/src/main/scala/webshop/webservice/ReserveItemsInstance.scala @@ -3,15 +3,16 @@ package webshop.webservice import cats.effect.{IO, Timer} import cats.implicits._ -import scala.concurrent.{ExecutionContext, Future} import scala.concurrent.duration._ +import scala.concurrent.{ExecutionContext, Future} -class ReserveItemsInstance()(implicit context: ExecutionContext) extends ReserveItems { - implicit val timer: Timer[IO] = IO.timer(context) +class ReserveItemsInstance extends ReserveItems { + private val ctx: ExecutionContext = concurrent.ExecutionContext.Implicits.global + private implicit val timer: Timer[IO] = IO.timer(ctx) override def apply(orderId: OrderId, items: List[Item]): Future[ReserveItemsOutput] = { - IO.sleep(1.second) - .as(ItemsReserved(ReservedItems(items, Array.fill(1000)(Byte.MaxValue)))) - .unsafeToFuture() + IO.sleep(1.second) + .as(ItemsReserved(ReservedItems(items, Array.fill(1000)(Byte.MaxValue)))) + .unsafeToFuture() } } \ No newline at end of file diff --git a/examples/baas-interaction-examples/ship-items/src/main/scala/webshop/webservice/ShipItemsInstance.scala b/examples/baas-interaction-examples/ship-items/src/main/scala/webshop/webservice/ShipItemsInstance.scala index 93c114fc..6631cf04 100644 --- a/examples/baas-interaction-examples/ship-items/src/main/scala/webshop/webservice/ShipItemsInstance.scala +++ b/examples/baas-interaction-examples/ship-items/src/main/scala/webshop/webservice/ShipItemsInstance.scala @@ -3,17 +3,18 @@ package webshop.webservice import cats.effect.{IO, Timer} import cats.implicits._ -import scala.concurrent.{ExecutionContext, Future} import scala.concurrent.duration._ +import scala.concurrent.{ExecutionContext, Future} -class ShipItemsInstance(implicit context: ExecutionContext) extends ShipItems { +class ShipItemsInstance extends ShipItems { + private val ctx: ExecutionContext = concurrent.ExecutionContext.Implicits.global - implicit val timer: Timer[IO] = IO.timer(context) + private implicit val timer: Timer[IO] = IO.timer(ctx) override def apply(order: ShippingOrder): Future[ShippingConfirmed] = { - IO.sleep(500.millis) - .as(ShippingConfirmed()) - .unsafeToFuture() + IO.sleep(500.millis) + .as(ShippingConfirmed()) + .unsafeToFuture() } } diff --git a/project/BuildInteractionDockerImageSBTPlugin.scala b/project/BuildInteractionDockerImageSBTPlugin.scala new file mode 100644 index 00000000..e8e3b38a --- /dev/null +++ b/project/BuildInteractionDockerImageSBTPlugin.scala @@ -0,0 +1,51 @@ +package baas.sbt + +import com.typesafe.sbt.packager.Keys.packageName +import com.typesafe.sbt.packager.archetypes.JavaAppPackaging +import com.typesafe.sbt.packager.docker.DockerPlugin +import com.typesafe.sbt.packager.docker.DockerPlugin.autoImport._ +import com.typesafe.sbt.packager.universal.UniversalPlugin.autoImport._ +import sbt.Keys._ +import sbt._ + + +object BuildInteractionDockerImageSBTPlugin extends sbt.AutoPlugin { + override def requires: Plugins = DockerPlugin && JavaAppPackaging + + override def trigger: PluginTrigger = allRequirements + + object autoImport { + + /** + * Example: "buildInteractionDockerImage docker:publishLocal net.bytebuddy:byte-buddy:1.10.8 Main" + */ + def buildDockerCommand: Command = Command.args("buildInteractionDockerImage", "") { (state, args) => + args match { + case commandName :: dependency :: entryPointClassName :: Nil => + val moduleID: ModuleID = dependency + .split(":") match { + case Array(organization, name, revision) => organization % name % revision + case other => throw new MessageOnlyException(s"Unexpected dependency declaration $other") + } + + val stateWithNewDependency = + Project.extract(state).appendWithSession(Seq( + libraryDependencies ++= Seq(moduleID), + packageName in Docker := s"interaction-${entryPointClassName.toLowerCase()}", + javaOptions in Universal += entryPointClassName + ), state) + + Command.process(commandName, stateWithNewDependency) + state + case _ => + throw new MessageOnlyException(s"Expected commandName dependency entryPointClassName") + } + } + } + + import autoImport._ + + override lazy val projectSettings: Seq[Def.Setting[_]] = Seq( + commands += buildDockerCommand + ) +} \ No newline at end of file diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 25380954..bda42527 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -47,7 +47,6 @@ object Dependencies { val levelDBJni = "org.fusesource.leveldbjni" % "leveldbjni-all" % "1.8" - val logback = "ch.qos.logback" % "logback-classic" % "1.2.3" val ficusConfig = "com.iheart" %% "ficus" % "1.4.7" val scalaGraph = "org.scala-graph" %% "graph-core" % "1.11.5"