Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Migrate project to sbt-projectmatrix #33

Merged
merged 7 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 8 additions & 36 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,19 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
scala: [2.13.11, 3.3.0]
scala: [2_13, 3_0]
java: [temurin@11]
scalaPlatform: [jvm]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout current branch (full)
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Java (temurin@11)
if: matrix.java == 'temurin@11'
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 11
Expand All @@ -49,19 +50,10 @@ jobs:
run: gem install jekyll -v 4.1.1

- name: Check that workflows are up to date
run: sbt '++ ${{ matrix.scala }}' githubWorkflowCheck
run: sbt githubWorkflowCheck

- name: Build project
run: sbt '++ ${{ matrix.scala }}' test makeMicrosite publishLocal

- name: Compress target directories
run: tar cf targets.tar modules/benchmarks/target target modules/munit/target docs/target modules/weaver/target modules/scalatest/target modules/core/target modules/cats/target modules/coretest/target project/target

- name: Upload target directories
uses: actions/upload-artifact@v3
with:
name: target-${{ matrix.os }}-${{ matrix.scala }}-${{ matrix.java }}
path: targets.tar
run: sbt 'test_${{ matrix.scala }}_${{ matrix.scalaPlatform }}' 'publishLocal_${{ matrix.scala }}_${{ matrix.scalaPlatform }}' makeMicrosite

publish:
name: Publish Artifacts
Expand All @@ -75,38 +67,18 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Checkout current branch (full)
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Java (temurin@11)
if: matrix.java == 'temurin@11'
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 11
cache: sbt

- name: Download target directories (2.13.11)
uses: actions/download-artifact@v3
with:
name: target-${{ matrix.os }}-2.13.11-${{ matrix.java }}

- name: Inflate target directories (2.13.11)
run: |
tar xf targets.tar
rm targets.tar

- name: Download target directories (3.3.0)
uses: actions/download-artifact@v3
with:
name: target-${{ matrix.os }}-3.3.0-${{ matrix.java }}

- name: Inflate target directories (3.3.0)
run: |
tar xf targets.tar
rm targets.tar

- name: Setup ruby
uses: ruby/setup-ruby@v1
with:
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/clean.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Delete artifacts
shell: bash {0}
run: |
# Customize those three lines with your repository and credentials:
REPO=${GITHUB_API_URL}/repos/${{ github.repository }}
Expand All @@ -25,7 +26,7 @@ jobs:
ghapi() { curl --silent --location --user _:$GITHUB_TOKEN "$@"; }

# A temporary file which receives HTTP response headers.
TMPFILE=/tmp/tmp.$$
TMPFILE=$(mktemp)

# An associative array, key: artifact name, value: number of artifacts of that name.
declare -A ARTCOUNT
Expand Down
69 changes: 53 additions & 16 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import sbt.internal.ProjectMatrix
import sbtghactions.JavaSpec
import complete.DefaultParsers._
import sbt.Reference.display

val munitVersion = "0.7.29"
val catsVersion = "2.9.0"
val scalatestVersion = "3.2.16"
val weaverVersion = "0.8.3"

val scala213 = "2.13.11"
val scala3 = "3.3.0"

val isScala3 = Def.setting {
// doesn't work well with >= 3.0.0 for `3.0.0-M1`
scalaVersion.value.startsWith("3")
}

val mainScalaVersion = Build.Scala213
val jvmScalaVersions = Seq(Build.Scala213, Build.Scala3)

inThisBuild(
List(
scalaVersion := scala213,
crossScalaVersions := Seq(scala213, scala3),
scalaVersion := mainScalaVersion,
organization := "com.github.jatcwang",
homepage := Some(url("https://github.com/jatcwang/difflicious")),
licenses := List("Apache-2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0")),
Expand All @@ -28,16 +30,21 @@ inThisBuild(
url("https://almostfunctional.com"),
),
),
commands ++= Build.createBuildCommands(allModules),
),
)

lazy val allModules = Seq(core, coretest, munit, scalatest, weaver, cats, benchmarks, docs).flatMap(_.projectRefs)

lazy val difflicious = Project("difflicious", file("."))
.aggregate(core, coretest, benchmarks, cats, docs, munit, scalatest, weaver)
.aggregate(allModules: _*)
.settings(commonSettings, noPublishSettings)

lazy val core = Project("difflicious-core", file("modules/core"))
lazy val core = projectMatrix
.in(file("modules/core"))
.settings(commonSettings)
.settings(
name := "difflicious-core",
libraryDependencies ++= Seq(
"dev.zio" %% "izumi-reflect" % "2.3.8",
"com.lihaoyi" %% "fansi" % "0.4.0",
Expand All @@ -46,58 +53,73 @@ lazy val core = Project("difflicious-core", file("modules/core"))
} else
Seq(
"com.softwaremill.magnolia1_2" %% "magnolia" % "1.0.0",
"org.scala-lang" % "scala-reflect" % scala213,
"org.scala-lang" % "scala-reflect" % Build.Scala213,
)),
Compile / sourceGenerators += Def.task {
val file = (Compile / sourceManaged).value / "difflicious" / "TupleDifferInstances.scala"
IO.write(file, TupleDifferInstancesGen.fileContent)
Seq(file)
}.taskValue,
)
.jvmPlatform(jvmScalaVersions)

lazy val munit = Project("difflicious-munit", file("modules/munit"))
lazy val munit = projectMatrix
.in(file("modules/munit"))
.dependsOn(core)
.settings(commonSettings)
.settings(
name := "difflicious-munit",
libraryDependencies ++= Seq(
"org.scalameta" %% "munit" % munitVersion,
),
)
.jvmPlatform(jvmScalaVersions)

lazy val scalatest = Project("difflicious-scalatest", file("modules/scalatest"))
lazy val scalatest = projectMatrix
.in(file("modules/scalatest"))
.dependsOn(core)
.settings(commonSettings)
.settings(
name := "difflicious-scalatest",
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest-core" % scalatestVersion,
),
)
.jvmPlatform(jvmScalaVersions)

lazy val weaver = Project("difflicious-weaver", file("modules/weaver"))
lazy val weaver = projectMatrix
.in(file("modules/weaver"))
.dependsOn(core)
.settings(commonSettings)
.settings(
name := "difflicious-weaver",
libraryDependencies ++= Seq(
"com.disneystreaming" %% "weaver-core" % weaverVersion,
),
)
.jvmPlatform(jvmScalaVersions)

lazy val cats = Project("difflicious-cats", file("modules/cats"))
lazy val cats = projectMatrix
.in(file("modules/cats"))
.dependsOn(core, coretest % "test->test")
.settings(commonSettings)
.settings(
name := "difflicious-cats",
libraryDependencies ++= Seq(
"org.typelevel" %% "cats-core" % catsVersion,
),
libraryDependencies ++= Seq(
"org.typelevel" %% "cats-laws" % catsVersion,
).map(_ % Test),
)
.jvmPlatform(jvmScalaVersions)

lazy val coretest = Project("coretest", file("modules/coretest"))
lazy val coretest = projectMatrix
.in(file("modules/coretest"))
.dependsOn(core)
.settings(commonSettings, noPublishSettings)
.settings(
name := "coretest",
libraryDependencies ++= Seq(
"org.typelevel" %% "cats-core" % catsVersion,
),
Expand All @@ -107,11 +129,13 @@ lazy val coretest = Project("coretest", file("modules/coretest"))
"org.scalameta" %% "munit-scalacheck" % munitVersion,
).map(_ % Test),
)
.jvmPlatform(jvmScalaVersions)

lazy val docs: Project = project
lazy val docs: ProjectMatrix = projectMatrix
.dependsOn(core, coretest, cats, munit, scalatest, weaver)
.enablePlugins(MicrositesPlugin)
.settings(
name := "docs",
commonSettings,
publish / skip := true,
)
Expand Down Expand Up @@ -157,12 +181,15 @@ lazy val docs: Project = project
(opts ++ extraOpts).filterNot(removes)
},
)
.jvmPlatform(Seq(Build.Scala213))

lazy val benchmarks = Project("benchmarks", file("modules/benchmarks"))
lazy val benchmarks = projectMatrix
.in(file("modules/benchmarks"))
.dependsOn(coretest)
.enablePlugins(JmhPlugin)
.settings(commonSettings)
.settings(noPublishSettings)
.jvmPlatform(jvmScalaVersions)

lazy val commonSettings = Seq(
scalacOptions --= {
Expand Down Expand Up @@ -213,15 +240,25 @@ val setupJekyllSteps = Seq(
),
)

ThisBuild / githubWorkflowBuildMatrixAdditions += ("scalaPlatform", List("jvm"))

ThisBuild / githubWorkflowBuildPreamble ++= setupJekyllSteps

ThisBuild / githubWorkflowPublishPreamble ++= setupJekyllSteps

ThisBuild / githubWorkflowScalaVersions := Seq("2_13", "3_0")

ThisBuild / githubWorkflowBuildSbtStepPreamble := Seq.empty

ThisBuild / githubWorkflowArtifactUpload := false
Copy link
Collaborator Author

@ghostbuster91 ghostbuster91 Mar 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to disable uploading of artifacts as sbt-gha does not generate list of artifacts to upload based on the matrix values but it generates it for all modules and there is no builtin way to configure it to this use-case. It fails with directory does not exist in our case as jvm-2.13 is not present when building for scala 3. There a workaround mentioned in sbt/sbt-github-actions#9 but I think that it doesn't apply to our case.

Maybe this can be fixed by overriding githubWorkflowGeneratedUploadSteps but readme discourages such actions.


// Add makeMicrosite to the build step
ThisBuild / githubWorkflowBuild ~= { steps =>
steps.map {
case w: WorkflowStep.Sbt if w.commands == List("test") =>
w.copy(commands = List("test", "makeMicrosite", "publishLocal"))
w.copy(commands =
List("test", "publishLocal").map(_ + "_${{ matrix.scala }}_${{ matrix.scalaPlatform }}") :+ "makeMicrosite",
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makeMicrosite will be run for every build matrix entry which is not ideal but I didn't find a way to make it conditional only for 2.13.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks no biggie we can fix that later.

)
case w => w
}
}
Expand Down
79 changes: 79 additions & 0 deletions project/Build.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import sbt._
import sbt.Keys._
import com.jsuereth.sbtpgp.PgpKeys._
import sbt.internal.LogManager
import sbt.internal.util.BufferedAppender
import java.io.PrintStream
import sbt.internal.ProjectMatrix
import sbtprojectmatrix.ProjectMatrixPlugin.autoImport.virtualAxes

object Build {

val Scala213 = "2.13.11"
val Scala3 = "3.3.0"

// copied from: https://github.com/disneystreaming/smithy4s/blob/21a6fb04ab3485c0a4b40fe205a628c6f4750813/project/Smithy4sBuildPlugin.scala#L508
def createBuildCommands(projects: Seq[ProjectReference]) = {
case class Doublet(scala: String, platform: String)

val scala3Suffix = VirtualAxis.scalaABIVersion(Scala3).idSuffix
val scala213Suffix = VirtualAxis.scalaABIVersion(Scala213).idSuffix
val jsSuffix = VirtualAxis.js.idSuffix
val nativeSuffix = VirtualAxis.native.idSuffix

val all: List[(Doublet, Seq[String])] =
projects
.collect { case lp: LocalProject =>
var projectId = lp.project

val scalaAxis =
if (projectId.endsWith(scala3Suffix)) {
projectId = projectId.dropRight(scala3Suffix.length)
"3_0"
} else "2_13"

val platformAxis =
if (projectId.endsWith(jsSuffix)) {
projectId = projectId.dropRight(jsSuffix.length)
"js"
} else if (projectId.endsWith(nativeSuffix)) {
projectId = projectId.dropRight(nativeSuffix.length)
"native"
} else {
"jvm"
}

Doublet(scalaAxis, platformAxis) -> lp.project
}
.groupBy(_._1)
.mapValues(_.map(_._2))
.toList

// some commands, like test and compile, are setup for all modules
val any = (t: Doublet) => true
// things like scalafix and scalafmt are only enabled on jvm 2.13 projects
val jvm2_13 = (t: Doublet) => t.scala == "2_13" && t.platform == "jvm"

val jvm = (t: Doublet) => t.platform == "jvm"

val desiredCommands: Map[String, (String, Doublet => Boolean)] = Map(
"test" -> ("test", any),
"compile" -> ("compile", any),
"publishLocal" -> ("publishLocal", any),
)

val cmds = all.flatMap { case (doublet, projects) =>
desiredCommands.filter(_._2._2(doublet)).map { case (name, (cmd, _)) =>
Command.command(
s"${name}_${doublet.scala}_${doublet.platform}",
) { state =>
projects.foldLeft(state) { case (st, proj) =>
s"$proj/$cmd" :: st
}
}
}
}

cmds
}
}
3 changes: 2 additions & 1 deletion project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.9.3")
addSbtPlugin("com.geirsson" % "sbt-ci-release" % "1.5.7")
addSbtPlugin("com.47deg" % "sbt-microsites" % "1.3.4")
addSbtPlugin("com.github.sbt" % "sbt-github-actions" % "0.15.0")
addSbtPlugin("com.github.sbt" % "sbt-github-actions" % "0.23.0")
addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.3.0") // override mdoc version from microsite
addSbtPlugin("com.eed3si9n" % "sbt-projectmatrix" % "0.9.1")