diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 2124e3413..000000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Build - -on: [push, pull_request] - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Set up JDK - uses: olafurpg/setup-scala@v13 - with: - java-version: 8 - - name: Cache SBT - uses: coursier/cache-action@v3 - - name: Start up Postgres - run: docker-compose up -d - - name: Run tests - run: sbt headerCheck +test docs/makeSite - - name: Shut down Postgres - run: docker-compose down diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..20bad0b61 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,161 @@ +# This file was automatically generated by sbt-github-actions using the +# githubWorkflowGenerate task. You should add and commit this file to +# your git repository. It goes without saying that you shouldn't edit +# this file by hand! Instead, if you wish to make changes, you should +# change your sbt build configuration to revise the workflow description +# to meet your needs, then regenerate this file. + +name: Continuous Integration + +on: + pull_request: + branches: ['**'] + push: + branches: ['**'] + 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: + build: + name: Build and Test + strategy: + matrix: + os: [ubuntu-latest] + scala: [2.12.15, 2.13.7, 3.1.0] + java: [temurin@11] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout current branch (full) + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Setup Java (temurin@11) + if: matrix.java == 'temurin@11' + uses: actions/setup-java@v2 + with: + distribution: temurin + java-version: 11 + + - name: Cache sbt + uses: actions/cache@v2 + with: + path: | + ~/.sbt + ~/.ivy2/cache + ~/.coursier/cache/v1 + ~/.cache/coursier/v1 + ~/AppData/Local/Coursier/Cache/v1 + ~/Library/Caches/Coursier/v1 + key: ${{ runner.os }}-sbt-cache-v2-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }} + + - name: Start up Postgres + run: docker-compose up -d + + - name: Check Headers + run: sbt ++${{ matrix.scala }} headerCheckAll + + - name: Check that workflows are up to date + run: sbt ++${{ matrix.scala }} githubWorkflowCheck + + - run: sbt ++${{ matrix.scala }} ci + + - name: Check Doc Site (2.13.7 only) + if: matrix.scala == '2.13.7' + run: sbt ++${{ matrix.scala }} docs/makeSite + + - name: Make target directories + run: mkdir -p modules/scalatest/target modules/refined/target target modules/postgres/target modules/docs/target modules/postgres-circe/target modules/h2/target modules/hikari/target modules/munit/target modules/h2-circe/target modules/core/target modules/example/target modules/specs2/target modules/free/target modules/bench/target project/target + + - name: Compress target directories + run: tar cf targets.tar modules/scalatest/target modules/refined/target target modules/postgres/target modules/docs/target modules/postgres-circe/target modules/h2/target modules/hikari/target modules/munit/target modules/h2-circe/target modules/core/target modules/example/target modules/specs2/target modules/free/target modules/bench/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' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') + strategy: + matrix: + os: [ubuntu-latest] + scala: [2.13.7] + java: [temurin@11] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout current branch (full) + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Setup Java (temurin@11) + if: matrix.java == 'temurin@11' + uses: actions/setup-java@v2 + with: + distribution: temurin + java-version: 11 + + - name: Cache sbt + uses: actions/cache@v2 + with: + path: | + ~/.sbt + ~/.ivy2/cache + ~/.coursier/cache/v1 + ~/.cache/coursier/v1 + ~/AppData/Local/Coursier/Cache/v1 + ~/Library/Caches/Coursier/v1 + key: ${{ runner.os }}-sbt-cache-v2-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }} + + - name: Download target directories (2.12.15) + uses: actions/download-artifact@v2 + with: + name: target-${{ matrix.os }}-2.12.15-${{ matrix.java }} + + - name: Inflate target directories (2.12.15) + run: | + tar xf targets.tar + rm targets.tar + + - name: Download target directories (2.13.7) + uses: actions/download-artifact@v2 + with: + name: target-${{ matrix.os }}-2.13.7-${{ matrix.java }} + + - name: Inflate target directories (2.13.7) + 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) + + - run: sbt ++${{ matrix.scala }} tlRelease diff --git a/.github/workflows/clean.yml b/.github/workflows/clean.yml new file mode 100644 index 000000000..547aaa43e --- /dev/null +++ b/.github/workflows/clean.yml @@ -0,0 +1,59 @@ +# This file was automatically generated by sbt-github-actions using the +# githubWorkflowGenerate task. You should add and commit this file to +# your git repository. It goes without saying that you shouldn't edit +# this file by hand! Instead, if you wish to make changes, you should +# change your sbt build configuration to revise the workflow description +# to meet your needs, then regenerate this file. + +name: Clean + +on: push + +jobs: + delete-artifacts: + name: Delete Artifacts + runs-on: ubuntu-latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - name: Delete artifacts + run: | + # Customize those three lines with your repository and credentials: + REPO=${GITHUB_API_URL}/repos/${{ github.repository }} + + # A shortcut to call GitHub API. + ghapi() { curl --silent --location --user _:$GITHUB_TOKEN "$@"; } + + # A temporary file which receives HTTP response headers. + TMPFILE=/tmp/tmp.$$ + + # An associative array, key: artifact name, value: number of artifacts of that name. + declare -A ARTCOUNT + + # Process all artifacts on this repository, loop on returned "pages". + URL=$REPO/actions/artifacts + while [[ -n "$URL" ]]; do + + # Get current page, get response headers in a temporary file. + JSON=$(ghapi --dump-header $TMPFILE "$URL") + + # Get URL of next page. Will be empty if we are at the last page. + URL=$(grep '^Link:' "$TMPFILE" | tr ',' '\n' | grep 'rel="next"' | head -1 | sed -e 's/.*.*//') + rm -f $TMPFILE + + # Number of artifacts on this page: + COUNT=$(( $(jq <<<$JSON -r '.artifacts | length') )) + + # Loop on all artifacts on this page. + for ((i=0; $i < $COUNT; i++)); do + + # Get name of artifact and count instances of this name. + name=$(jq <<<$JSON -r ".artifacts[$i].name?") + ARTCOUNT[$name]=$(( $(( ${ARTCOUNT[$name]} )) + 1)) + + id=$(jq <<<$JSON -r ".artifacts[$i].id?") + size=$(( $(jq <<<$JSON -r ".artifacts[$i].size_in_bytes?") )) + printf "Deleting '%s' #%d, %'d bytes\n" $name ${ARTCOUNT[$name]} $size + ghapi -X DELETE $REPO/actions/artifacts/$id + done + done diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 6ddef1869..000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Release -on: - push: - branches: [master] - tags: ["*"] -jobs: - publish: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: olafurpg/setup-scala@v13 - with: - java-version: 8 - - name: Cache SBT - uses: coursier/cache-action@v3 - - uses: olafurpg/setup-gpg@v3 - - name: Publish - run: sbt version "git status" ci-release "git status" - env: - PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} - PGP_SECRET: ${{ secrets.PGP_SECRET }} - SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} - SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} diff --git a/build.sbt b/build.sbt index f6a55561a..c43b1bda9 100644 --- a/build.sbt +++ b/build.sbt @@ -23,20 +23,43 @@ lazy val scala213Version = "2.13.7" lazy val scala30Version = "3.1.0" lazy val slf4jVersion = "1.7.32" -// These are releases to ignore during MiMa checks -lazy val botchedReleases = Set("0.8.0", "0.8.1") +// Basic versioning and publishing stuff +ThisBuild / tlBaseVersion := "1.0" +ThisBuild / tlCiReleaseBranches := Seq("main") // publish snapshits on `main` +ThisBuild / scalaVersion := scala213Version +ThisBuild / crossScalaVersions := Seq(scala212Version, scala213Version, scala30Version) +ThisBuild / developers += tlGitHubDev("tpolecat", "Rob Norris") +ThisBuild / tlSonatypeUseLegacyHost := false +ThisBuild / githubWorkflowJavaVersions := Seq(JavaSpec.temurin("11")) +ThisBuild / githubWorkflowBuildPreamble ++= Seq( + WorkflowStep.Run( + commands = List("docker-compose up -d"), + name = Some("Start up Postgres"), + ), + WorkflowStep.Sbt( + commands = List("headerCheckAll"), + name = Some("Check Headers"), + ), +) +ThisBuild / githubWorkflowBuildPostamble ++= Seq( + WorkflowStep.Sbt( + commands = List("docs/makeSite"), + name = Some(s"Check Doc Site ($scala213Version only)"), + cond = Some(s"matrix.scala == '$scala213Version'"), + ) +) // This is used in a couple places. Might be nice to separate these things out. lazy val postgisDep = "net.postgis" % "postgis-jdbc" % postGisVersion lazy val compilerFlags = Seq( - scalacOptions in (Compile, console) ++= Seq( + Compile / console / scalacOptions ++= Seq( "-Ydelambdafy:inline", // http://fs2.io/faq.html ), - scalacOptions in (Compile, doc) --= Seq( + Compile / doc / scalacOptions --= Seq( "-Xfatal-warnings" ), - scalacOptions in Test --= Seq( + Test / scalacOptions --= Seq( "-Xfatal-warnings" ), libraryDependencies ++= Seq( @@ -44,10 +67,6 @@ lazy val compilerFlags = Seq( ) ) -val isDotty = Def.setting( - CrossVersion.partialVersion(scalaVersion.value).exists(_._1 == 3) -) - lazy val buildSettings = Seq( organization := "org.tpolecat", licenses ++= Seq(("MIT", url("http://opensource.org/licenses/MIT"))) @@ -56,8 +75,6 @@ lazy val buildSettings = Seq( lazy val commonSettings = compilerFlags ++ Seq( - scalaVersion := scala213Version, - crossScalaVersions := Seq(scala212Version, scala213Version, scala30Version), // These sbt-header settings can't be set in ThisBuild for some reason headerMappings := headerMappings.value + (HeaderFileType.scala -> HeaderCommentStyle.cppStyleLineComment), @@ -69,16 +86,16 @@ lazy val commonSettings = )), // Scaladoc options - scalacOptions in (Compile, doc) ++= Seq( + Compile / doc / scalacOptions ++= Seq( "-groups", - "-sourcepath", (baseDirectory in LocalRootProject).value.getAbsolutePath, + "-sourcepath", (LocalRootProject / baseDirectory).value.getAbsolutePath, "-doc-source-url", "https://github.com/tpolecat/doobie/blob/v" + version.value + "€{FILE_PATH}.scala" ), // Kind Projector (Scala 2 only) libraryDependencies ++= Seq( compilerPlugin("org.typelevel" %% "kind-projector" % "0.13.2" cross CrossVersion.full), - ).filterNot(_ => isDotty.value), + ).filterNot(_ => tlIsScala3.value), // MUnit libraryDependencies ++= Seq( @@ -95,8 +112,8 @@ lazy val commonSettings = "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots", // Add some more source directories - unmanagedSourceDirectories in Compile ++= { - val sourceDir = (sourceDirectory in Compile).value + Compile / unmanagedSourceDirectories ++= { + val sourceDir = (Compile / sourceDirectory).value CrossVersion.partialVersion(scalaVersion.value) match { case Some((3, _)) => Seq(sourceDir / "scala-3") case Some((2, _)) => Seq(sourceDir / "scala-2") @@ -105,8 +122,8 @@ lazy val commonSettings = }, // Also for test - unmanagedSourceDirectories in Test ++= { - val sourceDir = (sourceDirectory in Test).value + Test / unmanagedSourceDirectories ++= { + val sourceDir = (Test / sourceDirectory).value CrossVersion.partialVersion(scalaVersion.value) match { case Some((3, _)) => Seq(sourceDir / "scala-3") case Some((2, _)) => Seq(sourceDir / "scala-2") @@ -117,7 +134,7 @@ lazy val commonSettings = // dottydoc really doesn't work at all right now Compile / doc / sources := { val old = (Compile / doc / sources).value - if (isDotty.value) + if (tlIsScala3.value) Seq() else old @@ -125,32 +142,18 @@ lazy val commonSettings = ) -lazy val publishSettings = Seq( - homepage := Some(url("https://github.com/tpolecat/doobie")), - developers := List( - Developer("tpolecat", "Rob Norris", "rob_norris@mac.com", url("http://www.tpolecat.org")) - ), - mappings in (Compile, packageSrc) ++= (managedSources in Compile).value pair sbt.io.Path.relativeTo(sourceManaged.value / "main" / "scala"), - mimaPreviousArtifacts ~= { as => as.filterNot(a => botchedReleases.contains(a.revision)) } -) - -lazy val noPublishSettings = Seq( - skip in publish := true, - mimaPreviousArtifacts := Set() -) - lazy val noDottySettings = Seq( - (publish / skip) := (publish / skip).value || isDotty.value, - (Compile / sources) := { if (isDotty.value) Seq() else (Compile / sources).value }, - (Test / sources) := { if (isDotty.value) Seq() else (Test / sources).value }, - libraryDependencies := libraryDependencies.value.filterNot(_ => isDotty.value), + (publish / skip) := (publish / skip).value || tlIsScala3.value, + (Compile / sources) := { if (tlIsScala3.value) Seq() else (Compile / sources).value }, + (Test / sources) := { if (tlIsScala3.value) Seq() else (Test / sources).value }, + libraryDependencies := libraryDependencies.value.filterNot(_ => tlIsScala3.value), ) lazy val doobieSettings = buildSettings ++ commonSettings lazy val doobie = project.in(file(".")) + .enablePlugins(NoPublishPlugin) .settings(doobieSettings) - .settings(noPublishSettings) .aggregate( bench, core, @@ -172,7 +175,6 @@ lazy val free = project .in(file("modules/free")) .enablePlugins(AutomateHeaderPlugin) .settings(doobieSettings) - .settings(publishSettings) .settings(freeGen2Settings) .settings( name := "doobie-free", @@ -186,8 +188,8 @@ lazy val free = project "org.typelevel" %% "cats-effect" % catsEffectVersion, ) ++Seq( scalaOrganization.value % "scala-reflect" % scalaVersion.value, // required for macros - ).filterNot(_ => isDotty.value), - freeGen2Dir := (scalaSource in Compile).value / "doobie" / "free", + ).filterNot(_ => tlIsScala3.value), + freeGen2Dir := (Compile / scalaSource).value / "doobie" / "free", freeGen2Package := "doobie.free", freeGen2Classes := { import java.sql._ @@ -216,26 +218,25 @@ lazy val core = project .enablePlugins(AutomateHeaderPlugin) .dependsOn(free) .settings(doobieSettings) - .settings(publishSettings) .settings( name := "doobie-core", description := "Pure functional JDBC layer for Scala.", libraryDependencies ++= Seq( "com.chuusai" %% "shapeless" % shapelessVersion, - ).filterNot(_ => isDotty.value) ++ Seq( + ).filterNot(_ => tlIsScala3.value) ++ Seq( "org.tpolecat" %% "typename" % "1.0.0", "com.h2database" % "h2" % h2Version % "test", ), scalacOptions += "-Yno-predef", - unmanagedSourceDirectories in Compile += { - val sourceDir = (sourceDirectory in Compile).value + Compile / unmanagedSourceDirectories += { + val sourceDir = (Compile / sourceDirectory).value CrossVersion.partialVersion(scalaVersion.value) match { case Some((2, n)) if n <= 12 => sourceDir / "scala-2.13-" case _ => sourceDir / "scala-2.13+" } }, - sourceGenerators in Compile += Def.task { - val outDir = (sourceManaged in Compile).value / "scala" / "doobie" + Compile / sourceGenerators += Def.task { + val outDir = (Compile / sourceManaged).value / "scala" / "doobie" val outFile = new File(outDir, "buildinfo.scala") outDir.mkdirs val v = version.value @@ -257,8 +258,9 @@ lazy val core = project lazy val example = project .in(file("modules/example")) + .enablePlugins(NoPublishPlugin) .enablePlugins(AutomateHeaderPlugin) - .settings(doobieSettings ++ noPublishSettings) + .settings(doobieSettings) .dependsOn(core, postgres, specs2, scalatest, hikari, h2) .settings( libraryDependencies ++= Seq( @@ -271,7 +273,6 @@ lazy val postgres = project .enablePlugins(AutomateHeaderPlugin) .dependsOn(core % "compile->compile;test->test") .settings(doobieSettings) - .settings(publishSettings) .settings(freeGen2Settings) .settings( name := "doobie-postgres", @@ -282,7 +283,7 @@ lazy val postgres = project postgisDep % "provided" ), scalacOptions -= "-Xfatal-warnings", // we need to do deprecated things - freeGen2Dir := (scalaSource in Compile).value / "doobie" / "postgres" / "free", + freeGen2Dir := (Compile / scalaSource).value / "doobie" / "postgres" / "free", freeGen2Package := "doobie.postgres.free", freeGen2Classes := { import java.sql._ @@ -314,7 +315,7 @@ lazy val postgres = project import org.postgresql.util._ import org.postgresql.geometric._ """, - initialCommands in consoleQuick := "" + consoleQuick / initialCommands := "" ) lazy val `postgres-circe` = project @@ -322,7 +323,6 @@ lazy val `postgres-circe` = project .enablePlugins(AutomateHeaderPlugin) .dependsOn(core, postgres) .settings(doobieSettings) - .settings(publishSettings) .settings( name := "doobie-postgres-circe", description := "Postgres circe support for doobie.", @@ -336,7 +336,6 @@ lazy val h2 = project .in(file("modules/h2")) .enablePlugins(AutomateHeaderPlugin) .settings(doobieSettings) - .settings(publishSettings) .dependsOn(core % "compile->compile;test->test") .settings( name := "doobie-h2", @@ -350,7 +349,6 @@ lazy val `h2-circe` = project .enablePlugins(AutomateHeaderPlugin) .dependsOn(core, h2) .settings(doobieSettings) - .settings(publishSettings) .settings( name := "doobie-h2-circe", description := "h2 circe support for doobie.", @@ -366,7 +364,6 @@ lazy val hikari = project .dependsOn(core) .dependsOn(postgres % "test") .settings(doobieSettings) - .settings(publishSettings) .settings( name := "doobie-hikari", description := "Hikari support for doobie.", @@ -385,7 +382,6 @@ lazy val specs2 = project .dependsOn(core) .dependsOn(h2 % "test") .settings(doobieSettings) - .settings(publishSettings) .settings( name := "doobie-specs2", description := "Specs2 support for doobie.", @@ -398,7 +394,6 @@ lazy val scalatest = project .enablePlugins(AutomateHeaderPlugin) .dependsOn(core) .settings(doobieSettings) - .settings(publishSettings) .settings( name := s"doobie-scalatest", description := "Scalatest support for doobie.", @@ -413,7 +408,6 @@ lazy val munit = project .enablePlugins(AutomateHeaderPlugin) .dependsOn(core) .settings(doobieSettings) - .settings(publishSettings) .settings( name := s"doobie-munit", description := "MUnit support for doobie.", @@ -426,21 +420,21 @@ lazy val munit = project lazy val bench = project .in(file("modules/bench")) + .enablePlugins(NoPublishPlugin) .enablePlugins(AutomateHeaderPlugin) .enablePlugins(JmhPlugin) .dependsOn(core, postgres) .settings(doobieSettings) - .settings(noPublishSettings) lazy val docs = project .in(file("modules/docs")) .dependsOn(core, postgres, specs2, munit, hikari, h2, scalatest) + .enablePlugins(NoPublishPlugin) .enablePlugins(ParadoxPlugin) .enablePlugins(ParadoxSitePlugin) .enablePlugins(GhpagesPlugin) .enablePlugins(MdocPlugin) .settings(doobieSettings) - .settings(noPublishSettings) .settings( scalacOptions := Nil, @@ -460,7 +454,7 @@ lazy val docs = project paradoxTheme := Some(builtinParadoxTheme("generic")), version := version.value.takeWhile(_ != '+'), // strip off the +3-f22dca22+20191110-1520-SNAPSHOT business paradoxProperties ++= Map( - "scala-versions" -> (crossScalaVersions in core).value.map(CrossVersion.partialVersion).flatten.map(_._2).mkString("2.", "/", ""), + "scala-versions" -> (core / crossScalaVersions).value.map(CrossVersion.partialVersion).flatten.map(_._2).mkString("2.", "/", ""), "org" -> organization.value, "scala.binary.version" -> s"2.${CrossVersion.partialVersion(scalaVersion.value).get._2}", "core-dep" -> s"${(core / name).value}_2.${CrossVersion.partialVersion(scalaVersion.value).get._2}", @@ -487,7 +481,6 @@ lazy val refined = project .enablePlugins(AutomateHeaderPlugin) .dependsOn(core) .settings(doobieSettings) - .settings(publishSettings) .settings( name := "doobie-refined", description := "Refined support for doobie.", diff --git a/project/plugins.sbt b/project/plugins.sbt index 9d2c6c26f..7b174d747 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,11 +1,10 @@ addSbtPlugin("com.lightbend.paradox" % "sbt-paradox" % "0.9.2") addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "1.4.1") addSbtPlugin("com.typesafe.sbt" % "sbt-ghpages" % "0.6.3") -addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.10") +addSbtPlugin("org.typelevel" % "sbt-typelevel-ci-release" % "0.4.0-M3") addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.9.3") addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.6.1") addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.3") addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.6.0") -addSbtPlugin("io.chrisdavenport" % "sbt-mima-version-check" % "0.1.2") addSbtPlugin("io.github.davidgregory084" % "sbt-tpolecat" % "0.1.20") addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.2.24")