From ae5ca756ed77aa5f82cee0fc8cfe00d7f9b563af Mon Sep 17 00:00:00 2001 From: Anton Sviridov Date: Sun, 20 Dec 2020 16:27:37 +0000 Subject: [PATCH] Render build matrix in the docs (#163) --- build.sbt | 70 +++++++++++- docs/installation.md | 21 +++- .../main/scala/weaver/MatrixRendering.scala | 105 ++++++++++++++++++ 3 files changed, 192 insertions(+), 4 deletions(-) create mode 100644 modules/docs/src/main/scala/weaver/MatrixRendering.scala diff --git a/build.sbt b/build.sbt index c7ac1552..63773f8d 100644 --- a/build.sbt +++ b/build.sbt @@ -48,6 +48,8 @@ lazy val allModules = Seq( effectFrameworks ).flatten +lazy val catsEffect3Version = "3.0.0-M4" + def catsEffectDependencies(proj: Project): Project = { proj.settings( libraryDependencies ++= { @@ -59,7 +61,7 @@ def catsEffectDependencies(proj: Project): Project = { else Seq( "co.fs2" %%% "fs2-core" % "3.0.0-M6", - "org.typelevel" %%% "cats-effect" % "3.0.0-M4" + "org.typelevel" %%% "cats-effect" % catsEffect3Version ) } ) @@ -89,6 +91,22 @@ lazy val core = projectMatrix } ) +lazy val projectsWithAxes = Def.task { + (name.value, virtualAxes.value, version.value) +} + +val allEffectCoresFilter: ScopeFilter = + ScopeFilter( + inProjects(effectFrameworks: _*), + inConfigurations(Compile) + ) + +val allIntegrationsCoresFilter: ScopeFilter = + ScopeFilter( + inProjects((scalacheck.projectRefs ++ specs2.projectRefs): _*), + inConfigurations(Compile) + ) + lazy val docs = projectMatrix .in(file("modules/docs")) .jvmPlatform(WeaverPlugin.supportedScalaVersions) @@ -105,7 +123,55 @@ lazy val docs = projectMatrix "org.http4s" %% "http4s-blaze-server" % "0.21.0", "org.http4s" %% "http4s-blaze-client" % "0.21.0", "com.lihaoyi" %% "fansi" % "0.2.7" - ) + ), + sourceGenerators in Compile += Def.taskDyn { + val filePath = + sourceManaged.in(Compile).value / "BuildMatrix.scala" + + def q(s: String) = '"' + s + '"' + + def process(f: Iterable[(String, Seq[VirtualAxis], String)]) = f.map { + case (name, axes, ver) => + val isJVM = axes.contains(VirtualAxis.jvm) + val isJS = axes.contains(VirtualAxis.js) + val scalaVersion = axes.collectFirst { + case a: VirtualAxis.ScalaVersionAxis => a + }.get.scalaVersion + + val CE = axes.collectFirst { + case CatsEffect2Axis => "CE2" + case CatsEffect3Axis => "CE3" + }.get + + List( + s"name = ${q(name)}", + s"jvm = $isJVM", + s"js = $isJS", + s"scalaVersion = ${q(scalaVersion)}", + s"catsEffect = $CE", + s"version = ${q(ver)}" + ).mkString("Artifact(", ",", ")") + }.mkString("List(", ",\n", ")") + + val effects = process(projectsWithAxes.all(allEffectCoresFilter).value) + val integrations = + process(projectsWithAxes.all(allIntegrationsCoresFilter).value) + + IO.write( + filePath, + s""" + | package weaver.docs + | + | object BuildMatrix { + | val catsEffect3Version = ${q(catsEffect3Version)} + | val effects = $effects + | val integrations = $integrations + | } + """.stripMargin + ) + + Def.task(Seq(filePath)) + } ) lazy val framework = projectMatrix diff --git a/docs/installation.md b/docs/installation.md index fe438071..255842b6 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -3,7 +3,25 @@ id: installation title: Installation --- -Weaver-test is currently published for **Scala 2.12 and 2.13** +All of the artifacts from the table below are: + +1. Available for **Scala 2.12 and 2.13** +2. Available for **JVM and Scala.js** + +```scala mdoc:passthrough +import weaver.docs._ + +val effects = Table + .create("Effect types", BuildMatrix.effects) + .render(BuildMatrix.catsEffect3Version) + +val integrations = Table + .create("Integrations", BuildMatrix.integrations) + .render(BuildMatrix.catsEffect3Version) + +println(effects) +println(integrations) +``` Weaver offers effect-type specific test frameworks. The Build setup depends on the effect-type library you've elected to use (or test against). @@ -14,4 +32,3 @@ Refer yourself to the library specific pages to get the correct configuration. * [monix](monix_usage.md) * [monix-bio](monix_bio_usage.md) * [zio](zio_usage.md) - diff --git a/modules/docs/src/main/scala/weaver/MatrixRendering.scala b/modules/docs/src/main/scala/weaver/MatrixRendering.scala new file mode 100644 index 00000000..c0125f97 --- /dev/null +++ b/modules/docs/src/main/scala/weaver/MatrixRendering.scala @@ -0,0 +1,105 @@ +package weaver.docs + +sealed trait CatsEffect +case object CE2 extends CatsEffect +case object CE3 extends CatsEffect + +case class Artifact( + name: String, + jvm: Boolean, + js: Boolean, + scalaVersion: String, + catsEffect: CatsEffect, + version: String +) + +case class Cell( + jvm: Boolean, + js: Boolean, + version: String +) + +case class Row( + name: String, + ce2: Option[Cell], + ce3: Option[Cell] +) + +case class Table( + name: String, + rows: Vector[Row] +) { + def _row(l: Seq[String], header: Boolean = false): String = { + val base = l.mkString("|", "|", "|") + + if (header) base + "\n" + _row(l.map(_ => "---"), false) + else base + "\n" + } + + def _cell(c: Option[Cell]): String = { + c match { + case Some(c) => + if (c.jvm && c.js) { + s"✅ `${c.version}`" + } else "❌" // TODO: do we always assume platform-complete artifacts? + case None => "❌" + } + } + + def render(catsEffect3Version: String) = { + val sb = new StringBuilder + sb.append(_row(Seq(name, "Cats Effect 2", s"Cats Effect $catsEffect3Version"), header = true)) + + rows.map { case Row(name, ce2, ce3) => + sb.append(_row(Seq(name, _cell(ce2), _cell(ce3)))) + } + sb.result() + } +} + +object Table { + def row_name(artif: String) = artif match { + case "cats" => "Cats-Effect" + case "zio" => "ZIO" + case "monix" => "Monix" + case "monix-bio" => "Monix BIO" + case "scalacheck" => "ScalaCheck" + case "specs2" => "Specs2 matchers" + case _ => throw new RuntimeException("Not another effect type!") + } + + def artifactsToCell(artifacts: List[Artifact]): Option[Cell] = { + artifacts.map(_.version).distinct.headOption.map { version => + val hasJVM = artifacts.exists(_.jvm) + val hasJS = artifacts.exists(_.js) + + Cell( + jvm = hasJVM, + js = hasJS, + version = version + ) + } + } + + def create(name: String, artifacts: List[Artifact]): Table = { + + val grouped = artifacts.groupBy(_.name) + + val rows = grouped.map { + case (name, artifacts) => + val rowName = row_name(name) + + val ce2Artifacts = artifacts.filter(_.catsEffect == CE2) + val ce3Artifacts = artifacts.filter(_.catsEffect == CE3) + + Row(rowName, + artifactsToCell(ce2Artifacts), + artifactsToCell(ce3Artifacts)) + } + + Table( + name, + rows.toVector.sortBy(_.name) + ) + } +}