diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8525523e6..eec901ec8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,10 @@ on: tags: [v*] env: + PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} + SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} + SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} + PGP_SECRET: ${{ secrets.PGP_SECRET }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: @@ -25,6 +29,16 @@ jobs: os: [ubuntu-latest] scala: [2.13.8, 3.1.0] java: [temurin@8, temurin@11, temurin@17] + project: [rootJS, rootJVM] + exclude: + - scala: 2.13.8 + java: temurin@11 + - scala: 2.13.8 + java: temurin@17 + - project: rootJS + java: temurin@11 + - project: rootJS + java: temurin@17 runs-on: ${{ matrix.os }} steps: - name: Checkout current branch (full) @@ -66,24 +80,44 @@ jobs: key: ${{ runner.os }}-sbt-cache-v2-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }} - name: Check that workflows are up to date - run: sbt ++${{ matrix.scala }} githubWorkflowCheck + run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' 'project /' githubWorkflowCheck - - name: Check headers+formatting - run: sbt ++${{ matrix.scala }} headerCheckAll scalafmtCheckAll scalafmtSbtCheck + - name: Check headers and formatting + run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' headerCheckAll scalafmtCheckAll 'project /' scalafmtSbtCheck - - name: Compile - run: sbt ++${{ matrix.scala }} Test/compile + - name: fastOptJS + if: matrix.project == 'rootJS' + run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' Test/fastOptJS - - name: Run tests - run: sbt ++${{ matrix.scala }} test + - name: Test + run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' test + + - name: Check binary compatibility + run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' mimaReportBinaryIssues + + - name: Generate API documentation + run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' doc - name: Build docs - run: sbt ++${{ matrix.scala }} doc docs/mdoc + if: matrix.project == 'rootJVM' + run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' doc docs/mdoc + + - name: Make target directories + run: mkdir -p data/.jvm/target legacy/.jvm/target extras/.js/target examples/target target platform/js/target macros/.jvm/target .js/target docs/target core/.js/target macros/.js/target laws/.js/target legacy/.js/target core/.jvm/target tests/js/target .jvm/target .native/target platform/jvm/target util/.js/target data/.js/target util/.jvm/target laws/.jvm/target tests/jvm/target extras/.jvm/target benchmark/target project/target + + - name: Compress target directories + run: tar cf targets.tar data/.jvm/target legacy/.jvm/target extras/.js/target examples/target target platform/js/target macros/.jvm/target .js/target docs/target core/.js/target macros/.js/target laws/.js/target legacy/.js/target core/.jvm/target tests/js/target .jvm/target .native/target platform/jvm/target util/.js/target data/.js/target util/.jvm/target laws/.jvm/target tests/jvm/target extras/.jvm/target benchmark/target project/target + + - name: Upload target directories + uses: actions/upload-artifact@v2 + with: + name: target-${{ matrix.os }}-${{ matrix.scala }}-${{ matrix.java }} + path: targets.tar publish: name: Publish Artifacts needs: [build] - if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')) + if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') strategy: matrix: os: [ubuntu-latest] @@ -129,9 +163,36 @@ jobs: ~/Library/Caches/Coursier/v1 key: ${{ runner.os }}-sbt-cache-v2-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }} - - env: - PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} - PGP_SECRET: ${{ secrets.PGP_SECRET }} - SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} - SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} - run: sbt ++${{ matrix.scala }} ci-release + - name: Download target directories (2.13.8) + uses: actions/download-artifact@v2 + with: + name: target-${{ matrix.os }}-2.13.8-${{ matrix.java }} + + - name: Inflate target directories (2.13.8) + run: | + tar xf targets.tar + rm targets.tar + + - name: Download target directories (3.1.0) + uses: actions/download-artifact@v2 + with: + name: target-${{ matrix.os }}-3.1.0-${{ matrix.java }} + + - name: Inflate target directories (3.1.0) + run: | + tar xf targets.tar + rm targets.tar + + - name: Import signing key + if: env.PGP_SECRET != '' && env.PGP_PASSPHRASE == '' + run: echo $PGP_SECRET | base64 -d | gpg --import + + - name: Import signing key and strip passphrase + if: env.PGP_SECRET != '' && env.PGP_PASSPHRASE != '' + run: | + echo "$PGP_SECRET" | base64 -d > /tmp/signing-key.gpg + echo "$PGP_PASSPHRASE" | gpg --pinentry-mode loopback --passphrase-fd 0 --import /tmp/signing-key.gpg + (echo "$PGP_PASSPHRASE"; echo; echo) | gpg --command-fd 0 --pinentry-mode loopback --change-passphrase $(gpg --list-secret-keys --with-colons 2> /dev/null | grep '^sec:' | cut --delimiter ':' --fields 5 | tail -n 1) + + - name: Publish + run: sbt '++${{ matrix.scala }}' tlRelease diff --git a/build.sbt b/build.sbt index 943126ed9..4cf597332 100644 --- a/build.sbt +++ b/build.sbt @@ -31,111 +31,39 @@ val Scala3 = "3.1.0" Global / onChangedBuildSource := ReloadOnSourceChanges -ThisBuild / crossScalaVersions := Seq(Scala213, Scala3) -ThisBuild / scalaVersion := Scala3 -ThisBuild / versionScheme := Some("early-semver") - -ThisBuild / githubWorkflowArtifactUpload := false +ThisBuild / tlBaseVersion := "0.18" +ThisBuild / crossScalaVersions := Seq(Scala213, Scala3) ThisBuild / githubWorkflowJavaVersions := Seq("8", "11", "17").map(JavaSpec.temurin(_)) -ThisBuild / githubWorkflowBuild := Seq( - WorkflowStep - .Sbt(List("headerCheckAll", "scalafmtCheckAll", "scalafmtSbtCheck"), name = Some("Check headers+formatting")), - WorkflowStep.Sbt(List("Test/compile"), name = Some("Compile")), - WorkflowStep.Sbt(List("test"), name = Some("Run tests")), - WorkflowStep.Sbt(List("doc", "docs/mdoc"), name = Some("Build docs")) -) - -inThisBuild( - List( - organization := "org.typelevel", - homepage := Some(url("https://typelevel.org/spire/")), - licenses += ("MIT", url("https://opensource.org/licenses/MIT")), - developers := List( - Developer( - "id_m", - "Erik Osheim", - "", - url("https://github.com/non/") - ), - Developer( - "tixxit", - "Tom Switzer", - "", - url("https://github.com/tixxit/") - ) - ) - ) -) - -ThisBuild / githubWorkflowTargetTags ++= Seq("v*") -ThisBuild / githubWorkflowPublishTargetBranches += - RefPredicate.StartsWith(Ref.Tag("v")) -ThisBuild / githubWorkflowPublish := Seq( - WorkflowStep.Sbt( - List("ci-release"), - env = Map( - "PGP_PASSPHRASE" -> "${{ secrets.PGP_PASSPHRASE }}", - "PGP_SECRET" -> "${{ secrets.PGP_SECRET }}", - "SONATYPE_PASSWORD" -> "${{ secrets.SONATYPE_PASSWORD }}", - "SONATYPE_USERNAME" -> "${{ secrets.SONATYPE_USERNAME }}" - ) +ThisBuild / githubWorkflowBuild += + WorkflowStep.Sbt(List("doc", "docs/mdoc"), name = Some("Build docs"), cond = Some("matrix.project == 'rootJVM'")) + +ThisBuild / homepage := Some(url("https://typelevel.org/spire/")) +ThisBuild / licenses := Seq("MIT" -> url("https://opensource.org/licenses/MIT")) +ThisBuild / developers := List( + Developer( + "id_m", + "Erik Osheim", + "", + url("https://github.com/non/") + ), + Developer( + "tixxit", + "Tom Switzer", + "", + url("https://github.com/tixxit/") ) ) -// Projects -lazy val spire = project - .in(file(".")) - .settings(moduleName := "spire-root") - .settings(spireSettings) - .settings(unidocSettings) - .settings(noPublishSettings) - .enablePlugins(ScalaUnidocPlugin) - .aggregate(spireJVM, spireJS) - .dependsOn(spireJVM, spireJS) +ThisBuild / tlFatalWarningsInCi := false -lazy val spireJVM = project - .in(file(".spireJVM")) - .settings(moduleName := "spire-aggregate") - .settings(spireSettings) - .settings(unidocSettings) - .settings(noPublishSettings) - .enablePlugins(ScalaUnidocPlugin) - .aggregate(macros.jvm, - core.jvm, - data.jvm, - extras.jvm, - examples, - laws.jvm, - legacy.jvm, - platform.jvm, - tests.jvm, - util.jvm, - benchmark - ) - .dependsOn(macros.jvm, - core.jvm, - data.jvm, - extras.jvm, - examples, - laws.jvm, - legacy.jvm, - platform.jvm, - tests.jvm, - util.jvm, - benchmark - ) +// Projects -lazy val spireJS = project - .in(file(".spireJS")) - .settings(moduleName := "spire-aggregate") +lazy val root = tlCrossRootProject + .aggregate(macros, core, data, extras, examples, laws, legacy, platform, tests, util, benchmark) .settings(spireSettings) .settings(unidocSettings) - .settings(noPublishSettings) .enablePlugins(ScalaUnidocPlugin) - .aggregate(macros.js, core.js, data.js, extras.js, laws.js, legacy.js, platform.js, tests.js, util.js) - .dependsOn(macros.js, core.js, data.js, extras.js, laws.js, legacy.js, platform.js, tests.js, util.js) - .enablePlugins(ScalaJSPlugin) lazy val platform = crossProject(JSPlatform, JVMPlatform) .settings(moduleName := "spire-platform") @@ -190,10 +118,10 @@ lazy val extras = crossProject(JSPlatform, JVMPlatform) .settings(moduleName := "spire-extras") .settings(spireSettings: _*) .settings(extrasSettings: _*) - .settings(crossVersionSharedSources: _*) .jvmSettings(commonJvmSettings: _*) .jsSettings(commonJsSettings: _*) .dependsOn(macros, platform, util, core, data) + lazy val docs = project .in(file("docs")) .enablePlugins(MicrositesPlugin) @@ -203,16 +131,20 @@ lazy val docs = project .settings(commonSettings: _*) .settings(spireSettings: _*) .settings(docSettings: _*) - .settings(noPublishSettings) + .enablePlugins(NoPublishPlugin) .enablePlugins(MdocPlugin) .settings( mdocIn := (Compile / sourceDirectory).value / "mdoc", - mdocVariables := Map( - "VERSION" -> (if (isSnapshot.value) - previousStableVersion.value.getOrElse(version.value) - else - version.value) - ), + mdocVariables := { + import sys.process._ + val currentRelease = + "git tag --list --sort=-v:refname".!!.split("\n").headOption + .map(_.trim) + .filter(_.startsWith("v")) + .map(_.tail) + .getOrElse(version.value) + Map("VERSION" -> currentRelease) + }, // NOTE: disable link hygine to supress dead link warnings because mdoc does not go well with Jekyll mdocExtraArguments ++= Seq("--no-link-hygiene") ) @@ -221,14 +153,13 @@ lazy val docs = project lazy val examples = project .settings(moduleName := "spire-examples") .settings(spireSettings) - .settings(crossVersionSharedSources: _*) .settings( libraryDependencies ++= Seq( "org.apfloat" % "apfloat" % apfloatVersion, "org.jscience" % "jscience" % jscienceVersion ) ) - .settings(noPublishSettings) + .enablePlugins(NoPublishPlugin) .settings(commonJvmSettings) .dependsOn(core.jvm, extras.jvm) @@ -251,7 +182,7 @@ lazy val tests = crossProject(JSPlatform, JVMPlatform) .settings(moduleName := "spire-tests") .settings(spireSettings: _*) .settings(munitSettings: _*) - .settings(noPublishSettings: _*) + .enablePlugins(NoPublishPlugin) .jvmSettings(commonJvmSettings: _*) .jsSettings(commonJsSettings: _*) .dependsOn(core, data, legacy, extras, laws) @@ -260,7 +191,7 @@ lazy val benchmark: Project = project .in(file("benchmark")) .settings(moduleName := "spire-benchmark") .settings(spireSettings) - .settings(noPublishSettings) + .enablePlugins(NoPublishPlugin) .settings(commonJvmSettings) .settings( libraryDependencies ++= Seq( @@ -272,19 +203,15 @@ lazy val benchmark: Project = project .enablePlugins(JmhPlugin) .dependsOn(core.jvm, extras.jvm) -// General settings - -addCommandAlias( - "validateJVM", - ";coreJVM/scalastyle;macrosJVM/test;coreJVM/test;extrasJVM/test;lawsJVM/test;testsJVM/test;examples/test;benchmark/test" +lazy val buildSettings = Seq( + scalacOptions := { + if (tlIsScala3.value) + scalacOptions.value.filterNot(Set("-source:3.0-migration")) + else + scalacOptions.value + } ) -addCommandAlias("validateJS", ";macrosJS/test;coreJS/test;extrasJS/test;lawsJS/test;testsJS/test") - -addCommandAlias("validate", ";validateJVM;validateJS") - -lazy val buildSettings = Seq() - lazy val commonDeps = Seq( libraryDependencies ++= Seq( "org.typelevel" %%% "algebra" % algebraVersion @@ -292,25 +219,11 @@ lazy val commonDeps = Seq( ) lazy val commonSettings = Seq( - scalacOptions ++= commonScalacOptions.value.diff( - Seq( - "-Xfatal-warnings", - "-language:existentials", - "-Ywarn-dead-code", - "-Ywarn-numeric-widen", - "-Ywarn-value-discard", - "-Xcheck-macros" - ) - ), resolvers += Resolver.sonatypeRepo("snapshots"), headerLicense := Some(HeaderLicense.Custom(header)) -) ++ scalaMacroDependencies ++ warnUnusedImport +) ++ scalaMacroDependencies -lazy val commonJsSettings = Seq( - Global / scalaJSStage := FastOptStage, - Test / parallelExecution := false, - scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.CommonJSModule) } -) +lazy val commonJsSettings = Seq() lazy val commonJvmSettings = Seq() @@ -416,11 +329,7 @@ lazy val coreSettings = Seq( } ) -lazy val extrasSettings = Seq( -// sourceGenerators in Compile <+= buildInfo, -// buildInfoKeys := Seq[BuildInfoKey](version, scalaVersion), -// buildInfoPackage := "spire.extras" -) +lazy val extrasSettings = Seq() lazy val genProductTypes = TaskKey[Seq[File]]("gen-product-types", "Generates several type classes for Tuple2-22.") @@ -439,70 +348,9 @@ lazy val unidocSettings = Seq( ScalaUnidoc / unidoc / unidocProjectFilter := inAnyProject -- inProjects(examples, benchmark, tests.jvm) ) -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Base Build Settings - Should not need to edit below this line. -// These settings could also come from another file or a plugin. -// The only issue if coming from a plugin is that the Macro lib versions -// are hard coded, so an overided facility would be required. - -addCommandAlias("gitSnapshots", ";set version in ThisBuild := git.gitDescribedVersion.value.get + \"-SNAPSHOT\"") - -lazy val noPublishSettings = Seq( - publish := (()), - publishLocal := (()), - publishArtifact := false -) - -lazy val crossVersionSharedSources: Seq[Setting[_]] = - Seq(Compile, Test).map { sc => - (sc / unmanagedSourceDirectories) ++= { - (sc / unmanagedSourceDirectories).value.map { dir: File => - CrossVersion.partialVersion(scalaVersion.value) match { - case Some((major, minor)) => - new File(s"${dir.getPath}_$major.$minor") - case None => - sys.error("couldn't parse scalaBinaryVersion ${scalaBinaryVersion.value}") - } - } - } - } - lazy val scalaMacroDependencies: Seq[Setting[_]] = Seq( libraryDependencies ++= { if (scalaVersion.value.startsWith("3")) Seq.empty else Seq(scalaOrganization.value % "scala-reflect" % scalaVersion.value % "provided") } ) - -lazy val commonScalacOptions = Def.setting( - Seq( - "-deprecation", - "-encoding", - "UTF-8", - "-feature", - "-language:existentials", - "-language:higherKinds", - "-language:implicitConversions", - "-language:experimental.macros", - "-unchecked", - "-Xfatal-warnings", - "-Ywarn-dead-code", - "-Ywarn-numeric-widen", - "-Ywarn-value-discard", - "-Xcheck-macros" - ) -) - -lazy val warnUnusedImport = Seq( - scalacOptions ++= { - CrossVersion.partialVersion(scalaVersion.value) match { - case Some((2, 10)) => - Seq() - case Some((2, n)) if (n >= 11) && (n <= 12) => - Seq("-Ywarn-unused-import") - case _ => Seq() - } - }, - Compile / console / scalacOptions ~= { _.filterNot("-Ywarn-unused-import" == _) }, - Test / console / scalacOptions := (Compile / console / scalacOptions).value -) diff --git a/project/plugins.sbt b/project/plugins.sbt index 9dbba6c74..1e1416db6 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,5 +1,7 @@ scalacOptions ++= Seq("-unchecked", "-deprecation", "-feature") +addSbtPlugin("org.typelevel" % "sbt-typelevel" % "0.4.0-M4") + addSbtPlugin("com.github.sbt" % "sbt-unidoc" % "0.5.0") addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.10.0") addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.3") @@ -8,11 +10,6 @@ addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "1.0.0") addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.8.0") addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.2.24") addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.9.2") -addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.1.0") addSbtPlugin("com.47deg" % "sbt-microsites" % "1.3.3") -addSbtPlugin("com.codecommit" % "sbt-github-actions" % "0.14.2") -addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6") -addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.10") -addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.6.0") libraryDependencies += "org.slf4j" % "slf4j-nop" % "1.7.33"