From 649c12e189c82227c24d892d0ad0de2dee30a9ae Mon Sep 17 00:00:00 2001 From: Michael Pilquist Date: Mon, 24 Jan 2022 09:09:34 -0500 Subject: [PATCH] Switch build to sbt-typelevel --- .github/workflows/ci.yml | 48 +++++++--- .scalafmt.conf | 12 ++- build.sbt | 88 +++++++++++-------- .../scala-3/scodec/bits/Interpolators.scala | 28 +++--- .../main/scala/scodec/bits/BitVector.scala | 3 +- .../main/scala/scodec/bits/ByteVector.scala | 3 +- project/plugins.sbt | 6 +- 7 files changed, 118 insertions(+), 70 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7ad2a84e..3b7cbebe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,10 +15,11 @@ on: tags: [v*] env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} + 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: build: @@ -26,8 +27,9 @@ jobs: strategy: matrix: os: [ubuntu-latest] - scala: [2.11.12, 2.12.15, 2.13.7, 3.1.0] + scala: [2.11.12, 2.12.15, 2.13.8, 3.1.0] java: [temurin@8] + project: [rootJS, rootJVM] runs-on: ${{ matrix.os }} steps: - name: Checkout current branch (full) @@ -55,12 +57,29 @@ 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 and formatting + run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' headerCheckAll scalafmtCheckAll 'project /' scalafmtSbtCheck + + - name: fastOptJS + if: matrix.project == 'rootJS' + run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' Test/fastOptJS - - run: sbt ++${{ matrix.scala }} ci + - 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: Make target directories + run: mkdir -p target .js/target core/js/target core/jvm/target .jvm/target .native/target benchmark/target project/target - name: Compress target directories - run: tar cf targets.tar target core/jvm/target core/js/target benchmark/target project/target + run: tar cf targets.tar target .js/target core/js/target core/jvm/target .jvm/target .native/target benchmark/target project/target - name: Upload target directories uses: actions/upload-artifact@v2 @@ -123,12 +142,12 @@ jobs: tar xf targets.tar rm targets.tar - - name: Download target directories (2.13.7) + - name: Download target directories (2.13.8) uses: actions/download-artifact@v2 with: - name: target-${{ matrix.os }}-2.13.7-${{ matrix.java }} + name: target-${{ matrix.os }}-2.13.8-${{ matrix.java }} - - name: Inflate target directories (2.13.7) + - name: Inflate target directories (2.13.8) run: | tar xf targets.tar rm targets.tar @@ -144,6 +163,15 @@ jobs: rm targets.tar - name: Import signing key + if: env.PGP_SECRET != '' && env.PGP_PASSPHRASE == '' run: echo $PGP_SECRET | base64 -d | gpg --import - - run: sbt ++${{ matrix.scala }} release + - 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/.scalafmt.conf b/.scalafmt.conf index 2e362e6f..7004c0b1 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,9 +1,19 @@ -version = "3.3.0" +version = "3.3.1" style = default +runner.dialect = scala213source3 + +fileOverride { + "glob:**/scala-3/**" { + runner.dialect = scala3 + } +} + maxColumn = 100 +docstrings.wrap = "no" + rewrite.rules = [ AvoidInfix RedundantBraces diff --git a/build.sbt b/build.sbt index e956522b..1f93f107 100644 --- a/build.sbt +++ b/build.sbt @@ -1,23 +1,19 @@ import com.typesafe.tools.mima.core._ -import sbtcrossproject.CrossPlugin.autoImport.{CrossType, crossProject} -import com.typesafe.sbt.SbtGit.GitKeys.{gitCurrentBranch, gitHeadCommit} addCommandAlias("fmt", "; compile:scalafmt; test:scalafmt; scalafmtSbt") addCommandAlias("fmtCheck", "; compile:scalafmtCheck; test:scalafmtCheck; scalafmtSbtCheck") -ThisBuild / baseVersion := "1.1" +ThisBuild / tlBaseVersion := "1.1" ThisBuild / organization := "org.scodec" ThisBuild / organizationName := "Scodec" -ThisBuild / homepage := Some(url("https://github.com/scodec/scodec-bits")) ThisBuild / startYear := Some(2013) -ThisBuild / crossScalaVersions := Seq("2.11.12", "2.12.15", "2.13.7", "3.1.0") +ThisBuild / crossScalaVersions := Seq("2.11.12", "2.12.15", "2.13.8", "3.1.0") -ThisBuild / strictSemVer := false - -ThisBuild / versionIntroduced := Map( +ThisBuild / tlVersionIntroduced := Map( + "3" -> "1.1.27", "2.13" -> "1.1.12", "2.12" -> "1.1.2", "2.11" -> "1.1.99" // Ignore 2.11 in mima @@ -25,9 +21,7 @@ ThisBuild / versionIntroduced := Map( ThisBuild / githubWorkflowJavaVersions := Seq(JavaSpec.temurin("8")) -ThisBuild / spiewakCiReleaseSnapshots := true - -ThisBuild / spiewakMainBranches := List("main") +ThisBuild / tlFatalWarningsInCi := false ThisBuild / scmInfo := Some( ScmInfo(url("https://github.com/scodec/scodec-bits"), "git@github.com:scodec/scodec-bits.git") @@ -37,16 +31,10 @@ ThisBuild / licenses := List( ("BSD-3-Clause", url("https://github.com/scodec/scodec-bits/blob/main/LICENSE")) ) -ThisBuild / publishGithubUser := "mpilquist" -ThisBuild / publishFullName := "Michael Pilquist" ThisBuild / developers ++= List( - "mpilquist" -> "Michael Pilquist", - "pchiusano" -> "Paul Chiusano" -).map { case (username, fullName) => - Developer(username, fullName, s"@$username", url(s"https://github.com/$username")) -} - -ThisBuild / fatalWarningsInCI := false + tlGitHubDev("mpilquist", "Michael Pilquist"), + tlGitHubDev("pchiusano", "Paul Chiusano") +) ThisBuild / mimaBinaryIssueFilters ++= Seq( ProblemFilters.exclude[IncompatibleResultTypeProblem]("scodec.bits.ByteVector.grouped"), @@ -73,36 +61,27 @@ ThisBuild / mimaBinaryIssueFilters ++= Seq( ProblemFilters.exclude[MissingClassProblem]("scodec.bits.LiteralSyntaxMacros$blackbox$"), ProblemFilters.exclude[MissingClassProblem]("scodec.bits.LiteralSyntaxMacros$blackbox$"), ProblemFilters.exclude[MissingClassProblem]("scodec.bits.ScalaVersionSpecific"), - ProblemFilters.exclude[IncompatibleMethTypeProblem]("scodec.bits.BitVector.reduceBalanced") + ProblemFilters.exclude[IncompatibleMethTypeProblem]("scodec.bits.BitVector.reduceBalanced"), + ProblemFilters.exclude[MissingClassProblem]("scodec.bits.BuildInfo"), + ProblemFilters.exclude[MissingClassProblem]("scodec.bits.BuildInfo$"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.crc.vectorTable") ) -lazy val root = project - .in(file(".")) - .aggregate(coreJVM, coreJS, benchmark) - .enablePlugins(NoPublishPlugin, SonatypeCiReleasePlugin) +lazy val root = tlCrossRootProject.aggregate(core, benchmark) lazy val core = crossProject(JVMPlatform, JSPlatform) .in(file("core")) - .enablePlugins(BuildInfoPlugin) .settings( name := "scodec-bits", libraryDependencies ++= { - if (isDotty.value) Nil + if (tlIsScala3.value) Nil else Seq("org.scala-lang" % "scala-reflect" % scalaVersion.value % "provided") }, - buildInfoPackage := "scodec.bits", - buildInfoKeys := Seq[BuildInfoKey](version, scalaVersion, gitHeadCommit), Compile / unmanagedResources ++= { val base = baseDirectory.value (base / "NOTICE") +: (base / "LICENSE") +: ((base / "licenses") * "LICENSE_*").get }, scalacOptions := scalacOptions.value.filterNot(_ == "-source:3.0-migration"), - Compile / unmanagedSourceDirectories ++= { - val major = if (isDotty.value) "-3" else "-2" - List(CrossType.Pure, CrossType.Full).flatMap( - _.sharedSrcDir(baseDirectory.value, "main").toList.map(f => file(f.getPath + major)) - ) - }, libraryDependencies += "org.scalameta" %%% "munit-scalacheck" % "0.7.29" % "test" ) @@ -114,7 +93,44 @@ lazy val coreJVM = core.jvm ) lazy val coreJS = core.js.settings( - scalaJSLinkerConfig ~= (_.withModuleKind(ModuleKind.CommonJSModule)) + scalaJSLinkerConfig ~= (_.withModuleKind(ModuleKind.CommonJSModule)), + // Override JS versions, as older stuff built for SJS 0.6 + tlVersionIntroduced := tlVersionIntroduced.value ++ Map( + "2.13" -> "1.1.14", + "2.12" -> "1.1.14" + ), + mimaBinaryIssueFilters ++= Seq( + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.BitVector.deflate"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.BitVector.deflate$default$1"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.BitVector.deflate$default$2"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.BitVector.deflate$default$3"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.BitVector.deflate$default$4"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.BitVector.inflate"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.BitVector.inflate$default$1"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.BitVector.digest"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.BitVector.digest"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.BitVector.encrypt"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.BitVector.encrypt$default$3"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.BitVector.decrypt"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.BitVector.decrypt$default$3"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.ByteVector.deflate"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.ByteVector.deflate$default$1"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.ByteVector.deflate$default$2"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.ByteVector.deflate$default$3"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.ByteVector.deflate$default$4"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.ByteVector.inflate"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.ByteVector.inflate$default$1"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.ByteVector.inflate$default$2"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.ByteVector.digest"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.ByteVector.encrypt"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.ByteVector.encrypt$default$3"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.ByteVector.decrypt"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.ByteVector.decrypt$default$3"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.BitVector.cipher"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.BitVector.cipher$default$4"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.ByteVector.cipher"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scodec.bits.ByteVector.cipher$default$4") + ) ) lazy val benchmark: Project = project diff --git a/core/shared/src/main/scala-3/scodec/bits/Interpolators.scala b/core/shared/src/main/scala-3/scodec/bits/Interpolators.scala index 56878bc6..59615f80 100644 --- a/core/shared/src/main/scala-3/scodec/bits/Interpolators.scala +++ b/core/shared/src/main/scala-3/scodec/bits/Interpolators.scala @@ -32,27 +32,27 @@ package scodec.bits import scala.quoted.* -/** - * Provides the `hex` string interpolator, which returns `ByteVector` instances from hexadecimal strings. - * +/** Provides the `hex` string interpolator, which returns `ByteVector` instances from hexadecimal strings. + * * @example {{{ * scala> val b = hex"deadbeef" * val b: scodec.bits.ByteVector = ByteVector(4 bytes, 0xdeadbeef) * }}} */ -extension (inline ctx: StringContext) inline def hex (inline args: Any*): ByteVector = - ${Literals.Hex('ctx, 'args)} +extension (inline ctx: StringContext) + inline def hex(inline args: Any*): ByteVector = + ${ Literals.Hex('ctx, 'args) } -/** - * Provides the `bin` string interpolator, which returns `BitVector` instances from binary strings. +/** Provides the `bin` string interpolator, which returns `BitVector` instances from binary strings. * * @example {{{ * scala> val b = bin"1010101010" * val b: scodec.bits.BitVector = BitVector(10 bits, 0xaa8) * }}} */ -extension (inline ctx: StringContext) inline def bin (inline args: Any*): BitVector = - ${Literals.Bin('ctx, 'args)} +extension (inline ctx: StringContext) + inline def bin(inline args: Any*): BitVector = + ${ Literals.Bin('ctx, 'args) } object Literals: @@ -78,15 +78,15 @@ object Literals: else quotes.reflect.report.error("interpolation not supported", argsExpr) ??? - + object Hex extends Validator[ByteVector]: def validate(s: String)(using Quotes): Either[String, Expr[ByteVector]] = ByteVector.fromHex(s) match - case None => Left("hexadecimal string literal may only contain characters [0-9a-fA-f]") - case Some(_) => Right('{ByteVector.fromValidHex(${Expr(s)})}) + case None => Left("hexadecimal string literal may only contain characters [0-9a-fA-f]") + case Some(_) => Right('{ ByteVector.fromValidHex(${ Expr(s) }) }) object Bin extends Validator[BitVector]: def validate(s: String)(using Quotes): Either[String, Expr[BitVector]] = ByteVector.fromBin(s) match - case None => Left("binary string literal may only contain characters [0, 1]") - case Some(_) => Right('{BitVector.fromValidBin(${Expr(s)})}) + case None => Left("binary string literal may only contain characters [0, 1]") + case Some(_) => Right('{ BitVector.fromValidBin(${ Expr(s) }) }) diff --git a/core/shared/src/main/scala/scodec/bits/BitVector.scala b/core/shared/src/main/scala/scodec/bits/BitVector.scala index e61034db..d0a2b04d 100644 --- a/core/shared/src/main/scala/scodec/bits/BitVector.scala +++ b/core/shared/src/main/scala/scodec/bits/BitVector.scala @@ -1899,7 +1899,7 @@ object BitVector extends BitVectorCompanionCrossPlatform { val shiftedByWholeBytes: ByteVector = underlying.underlying.slice(lowByte, lowByte + bytesNeededForBits(newSize) + 1) val bitsToShiftEachByte = (low % 8).toInt - val newBytes = { + val newBytes = if (bitsToShiftEachByte == 0) shiftedByWholeBytes else shiftedByWholeBytes.zipWithI(shiftedByWholeBytes.drop(1) :+ (0: Byte)) { case (a, b) => @@ -1908,7 +1908,6 @@ object BitVector extends BitVectorCompanionCrossPlatform { ((b & topNBits(bitsToShiftEachByte)) & 0x000000ff) >>> (8 - bitsToShiftEachByte) hi | low } - } toBytes( if (newSize <= (newBytes.size - 1) * 8) newBytes.dropRight(1) else newBytes, newSize diff --git a/core/shared/src/main/scala/scodec/bits/ByteVector.scala b/core/shared/src/main/scala/scodec/bits/ByteVector.scala index 70e00ffb..a1b68a48 100644 --- a/core/shared/src/main/scala/scodec/bits/ByteVector.scala +++ b/core/shared/src/main/scala/scodec/bits/ByteVector.scala @@ -1991,7 +1991,7 @@ object ByteVector extends ByteVectorCompanionCrossPlatform { str(idx) match { case c if alphabet.ignore(c) => // ignore case c => - val cidx = { + val cidx = if (padding == 0) if (c == Pad) if (mod == 2 || mod == 3) { @@ -2015,7 +2015,6 @@ object ByteVector extends ByteVectorCompanionCrossPlatform { return Left( s"Unexpected character '$c' at index $idx after padding character; only '=' and whitespace characters allowed after first padding character" ) - } mod match { case 0 => buffer = cidx & 0x3f diff --git a/project/plugins.sbt b/project/plugins.sbt index ef778086..f75cbeac 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,7 +1,3 @@ +addSbtPlugin("org.typelevel" % "sbt-typelevel" % "0.4.1") addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.8.0") -addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.1.0") addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.3") -addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.10.0") -addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6") -addSbtPlugin("com.codecommit" % "sbt-github-actions" % "0.14.2") -addSbtPlugin("com.codecommit" % "sbt-spiewak-sonatype" % "0.23.0")