From cf82b87826dc9eee773d2e8742ca26846a69917e Mon Sep 17 00:00:00 2001 From: David Gregory <2992938+DavidGregory084@users.noreply.github.com> Date: Mon, 31 Jul 2023 13:32:42 +0100 Subject: [PATCH 1/3] Try using sbt-scalafix for Scalafix build migrations --- .../core/buildtool/sbt/SbtAlg.scala | 60 ++++-- .../core/buildtool/sbt/SbtAlgTest.scala | 178 ++++++++++++++++++ 2 files changed, 225 insertions(+), 13 deletions(-) diff --git a/modules/core/src/main/scala/org/scalasteward/core/buildtool/sbt/SbtAlg.scala b/modules/core/src/main/scala/org/scalasteward/core/buildtool/sbt/SbtAlg.scala index 19460a3cfd..aa63728e4f 100644 --- a/modules/core/src/main/scala/org/scalasteward/core/buildtool/sbt/SbtAlg.scala +++ b/modules/core/src/main/scala/org/scalasteward/core/buildtool/sbt/SbtAlg.scala @@ -25,15 +25,15 @@ import org.scalasteward.core.buildtool.sbt.command._ import org.scalasteward.core.buildtool.{BuildRoot, BuildToolAlg} import org.scalasteward.core.coursier.VersionsCache import org.scalasteward.core.data.{Dependency, Scope, Version} -import org.scalasteward.core.edit.scalafix.{ScalafixCli, ScalafixMigration} +import org.scalasteward.core.edit.scalafix.ScalafixMigration import org.scalasteward.core.io.process.SlurpOptions import org.scalasteward.core.io.{FileAlg, FileData, ProcessAlg, WorkspaceAlg} import org.scalasteward.core.util.Nel +import org.scalasteward.core.buildtool.sbt.scalaStewardSbtScalafix final class SbtAlg[F[_]](config: Config)(implicit fileAlg: FileAlg[F], processAlg: ProcessAlg[F], - scalafixCli: ScalafixCli[F], workspaceAlg: WorkspaceAlg[F], versionsCache: VersionsCache[F], F: Concurrent[F] @@ -129,18 +129,52 @@ final class SbtAlg[F[_]](config: Config)(implicit .getVersions(Scope(sbtScalafixDependency, List(config.defaultResolver)), None) .map(_.lastOption) + private def addScalafixPluginTemporarily( + buildRootDir: File, + pluginVersion: Version, + metaBuilds: Int + ): Resource[F, Unit] = { + val plugin = scalaStewardSbtScalafix(pluginVersion) + List + .iterate(buildRootDir / project / project, metaBuilds + 1)(_ / project) + .collectFold(fileAlg.createTemporarily(_, plugin)) + } + + private def addScalacOptionsTemporarily( + buildRootDir: File, + scalacOptions: Option[Nel[String]], + metaBuilds: Int + ): Resource[F, Unit] = + scalacOptions.fold(Resource.unit[F]) { opts => + val options = scalaStewardScalafixOptions(opts.toList) + List + .iterate(buildRootDir / project, metaBuilds + 1)(_ / project) + .collectFold(fileAlg.createTemporarily(_, options)) + } + private def runBuildMigration(buildRoot: BuildRoot, migration: ScalafixMigration): F[Unit] = - for { - buildRootDir <- workspaceAlg.buildRootDir(buildRoot) - projectDir = buildRootDir / project - files0 <- ( - fileAlg.walk(buildRootDir, 1).filter(_.extension.contains(".sbt")) ++ - fileAlg.walk(projectDir, 3).filter(_.extension.exists(Set(".sbt", ".scala"))) - ).compile.toList - _ <- Nel.fromList(files0).fold(F.unit) { files1 => - scalafixCli.runMigration(buildRootDir, files1, migration) - } - } yield () + OptionT(latestSbtScalafixVersion).foreachF { pluginVersion => + for { + buildRootDir <- workspaceAlg.buildRootDir(buildRoot) + metaBuilds <- metaBuildsCount(buildRootDir) + _ <- addScalafixPluginTemporarily(buildRootDir, pluginVersion, metaBuilds).surround { + addScalacOptionsTemporarily(buildRootDir, migration.scalacOptions, metaBuilds).surround { + val scalafixCmds = migration.rewriteRules.map(rule => s"$scalafixAll $rule").toList + val slurpOptions = SlurpOptions.ignoreBufferOverflow + val commands = Nel.fromList( + List.fill(metaBuilds + 1)(List(reloadPlugins, scalafixEnable) ++ scalafixCmds).flatten + ) + commands.fold(F.unit) { cmds => + sbt( + cmds, + buildRootDir, + slurpOptions + ).void + } + } + } + } yield () + } private def sbt( sbtCommands: Nel[String], diff --git a/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/SbtAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/SbtAlgTest.scala index f065d8916a..a22b7b064f 100644 --- a/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/SbtAlgTest.scala +++ b/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/SbtAlgTest.scala @@ -125,6 +125,184 @@ class SbtAlgTest extends FunSuite { assertEquals(state, expected) } + test("runMigrations: build migration") { + val repo = Repo("sbt-alg", "test-build-migration-1") + val buildRoot = BuildRoot(repo, ".") + val repoDir = workspaceAlg.repoDir(repo).unsafeRunSync() + val migration = ScalafixMigration( + groupId = GroupId("io.github.davidgregory084"), + artifactIds = Nel.of("sbt-tpolecat"), + newVersion = Version("0.5.0"), + rewriteRules = Nel.of("github:typelevel/sbt-tpolecat/v0_5?sha=v0.5.0"), + target = Some(ScalafixMigration.Target.Build) + ) + val initialState = MockState.empty + .addFiles( + workspace / s"store/versions/v2/https/repo1.maven.org/maven2/ch/epfl/scala/sbt-scalafix_2.12_1.0/versions.json" -> sbtScalafixVersionJson + ) + .unsafeRunSync() + val state = sbtAlg.runMigration(buildRoot, migration).runS(initialState).unsafeRunSync() + val expected = initialState.copy( + trace = Vector( + Cmd( + "read", + s"$workspace/store/versions/v2/https/repo1.maven.org/maven2/ch/epfl/scala/sbt-scalafix_2.12_1.0/versions.json" + ), + Cmd("test", "-d", s"$repoDir/project"), + Cmd("write", s"$repoDir/project/project/scala-steward-sbt-scalafix.sbt"), + Cmd.execSandboxed( + repoDir, + "sbt", + "-Dsbt.color=false", + "-Dsbt.log.noformat=true", + "-Dsbt.supershell=false", + "-Dsbt.server.forcestart=true", + s";$reloadPlugins;$scalafixEnable;$scalafixAll github:typelevel/sbt-tpolecat/v0_5?sha=v0.5.0" + ), + Cmd("rm", "-rf", s"$repoDir/project/project/scala-steward-sbt-scalafix.sbt") + ) + ) + assertEquals(state, expected) + } + + test("runMigrations: build migration with meta-build") { + val repo = Repo("sbt-alg", "test-build-migration-2") + val buildRoot = BuildRoot(repo, ".") + val repoDir = workspaceAlg.repoDir(repo).unsafeRunSync() + val migration = ScalafixMigration( + groupId = GroupId("io.github.davidgregory084"), + artifactIds = Nel.of("sbt-tpolecat"), + newVersion = Version("0.5.0"), + rewriteRules = Nel.of("github:typelevel/sbt-tpolecat/v0_5?sha=v0.5.0"), + target = Some(ScalafixMigration.Target.Build) + ) + val initialState = MockState.empty + .addFiles( + repoDir / "project" / "Dependencies.scala" -> "object Dependencies", // put anything at all into the meta-build + workspace / s"store/versions/v2/https/repo1.maven.org/maven2/ch/epfl/scala/sbt-scalafix_2.12_1.0/versions.json" -> sbtScalafixVersionJson + ) + .unsafeRunSync() + val state = sbtAlg.runMigration(buildRoot, migration).runS(initialState).unsafeRunSync() + val expected = initialState.copy( + trace = Vector( + Cmd( + "read", + s"$workspace/store/versions/v2/https/repo1.maven.org/maven2/ch/epfl/scala/sbt-scalafix_2.12_1.0/versions.json" + ), + Cmd("test", "-d", s"$repoDir/project"), + Cmd("test", "-d", s"$repoDir/project/project"), + Cmd("write", s"$repoDir/project/project/scala-steward-sbt-scalafix.sbt"), + Cmd("write", s"$repoDir/project/project/project/scala-steward-sbt-scalafix.sbt"), + Cmd.execSandboxed( + repoDir, + "sbt", + "-Dsbt.color=false", + "-Dsbt.log.noformat=true", + "-Dsbt.supershell=false", + "-Dsbt.server.forcestart=true", + s";$reloadPlugins;$scalafixEnable;$scalafixAll github:typelevel/sbt-tpolecat/v0_5?sha=v0.5.0" + + s";$reloadPlugins;$scalafixEnable;$scalafixAll github:typelevel/sbt-tpolecat/v0_5?sha=v0.5.0" + ), + Cmd("rm", "-rf", s"$repoDir/project/project/project/scala-steward-sbt-scalafix.sbt"), + Cmd("rm", "-rf", s"$repoDir/project/project/scala-steward-sbt-scalafix.sbt") + ) + ) + assertEquals(state, expected) + } + + test("runMigrations: build migration with scalacOptions") { + val repo = Repo("sbt-alg", "test-build-migration-3") + val buildRoot = BuildRoot(repo, ".") + val repoDir = workspaceAlg.repoDir(repo).unsafeRunSync() + val migration = ScalafixMigration( + groupId = GroupId("io.github.davidgregory084"), + artifactIds = Nel.of("sbt-tpolecat"), + newVersion = Version("0.5.0"), + rewriteRules = Nel.of("github:typelevel/sbt-tpolecat/v0_5?sha=v0.5.0"), + scalacOptions = Some(Nel.of("-P:semanticdb:synthetics:on")), + target = Some(ScalafixMigration.Target.Build) + ) + val initialState = MockState.empty + .addFiles( + workspace / s"store/versions/v2/https/repo1.maven.org/maven2/ch/epfl/scala/sbt-scalafix_2.12_1.0/versions.json" -> sbtScalafixVersionJson + ) + .unsafeRunSync() + val state = sbtAlg.runMigration(buildRoot, migration).runS(initialState).unsafeRunSync() + val expected = initialState.copy( + trace = Vector( + Cmd( + "read", + s"$workspace/store/versions/v2/https/repo1.maven.org/maven2/ch/epfl/scala/sbt-scalafix_2.12_1.0/versions.json" + ), + Cmd("test", "-d", s"$repoDir/project"), + Cmd("write", s"$repoDir/project/project/scala-steward-sbt-scalafix.sbt"), + Cmd("write", s"$repoDir/project/scala-steward-scalafix-options.sbt"), + Cmd.execSandboxed( + repoDir, + "sbt", + "-Dsbt.color=false", + "-Dsbt.log.noformat=true", + "-Dsbt.supershell=false", + "-Dsbt.server.forcestart=true", + s";$reloadPlugins;$scalafixEnable;$scalafixAll github:typelevel/sbt-tpolecat/v0_5?sha=v0.5.0" + ), + Cmd("rm", "-rf", s"$repoDir/project/scala-steward-scalafix-options.sbt"), + Cmd("rm", "-rf", s"$repoDir/project/project/scala-steward-sbt-scalafix.sbt") + ) + ) + assertEquals(state, expected) + } + + test("runMigrations: build migration with scalacOptions and meta-build") { + val repo = Repo("sbt-alg", "test-build-migration-4") + val buildRoot = BuildRoot(repo, ".") + val repoDir = workspaceAlg.repoDir(repo).unsafeRunSync() + val migration = ScalafixMigration( + groupId = GroupId("io.github.davidgregory084"), + artifactIds = Nel.of("sbt-tpolecat"), + newVersion = Version("0.5.0"), + rewriteRules = Nel.of("github:typelevel/sbt-tpolecat/v0_5?sha=v0.5.0"), + scalacOptions = Some(Nel.of("-P:semanticdb:synthetics:on")), + target = Some(ScalafixMigration.Target.Build) + ) + val initialState = MockState.empty + .addFiles( + repoDir / "project" / "Dependencies.scala" -> "object Dependencies", // put anything at all into the meta-build + workspace / s"store/versions/v2/https/repo1.maven.org/maven2/ch/epfl/scala/sbt-scalafix_2.12_1.0/versions.json" -> sbtScalafixVersionJson + ) + .unsafeRunSync() + val state = sbtAlg.runMigration(buildRoot, migration).runS(initialState).unsafeRunSync() + val expected = initialState.copy( + trace = Vector( + Cmd( + "read", + s"$workspace/store/versions/v2/https/repo1.maven.org/maven2/ch/epfl/scala/sbt-scalafix_2.12_1.0/versions.json" + ), + Cmd("test", "-d", s"$repoDir/project"), + Cmd("test", "-d", s"$repoDir/project/project"), + Cmd("write", s"$repoDir/project/project/scala-steward-sbt-scalafix.sbt"), + Cmd("write", s"$repoDir/project/project/project/scala-steward-sbt-scalafix.sbt"), + Cmd("write", s"$repoDir/project/scala-steward-scalafix-options.sbt"), + Cmd("write", s"$repoDir/project/project/scala-steward-scalafix-options.sbt"), + Cmd.execSandboxed( + repoDir, + "sbt", + "-Dsbt.color=false", + "-Dsbt.log.noformat=true", + "-Dsbt.supershell=false", + "-Dsbt.server.forcestart=true", + s";$reloadPlugins;$scalafixEnable;$scalafixAll github:typelevel/sbt-tpolecat/v0_5?sha=v0.5.0" + + s";$reloadPlugins;$scalafixEnable;$scalafixAll github:typelevel/sbt-tpolecat/v0_5?sha=v0.5.0" + ), + Cmd("rm", "-rf", s"$repoDir/project/project/scala-steward-scalafix-options.sbt"), + Cmd("rm", "-rf", s"$repoDir/project/scala-steward-scalafix-options.sbt"), + Cmd("rm", "-rf", s"$repoDir/project/project/project/scala-steward-sbt-scalafix.sbt"), + Cmd("rm", "-rf", s"$repoDir/project/project/scala-steward-sbt-scalafix.sbt") + ) + ) + assertEquals(state, expected) + } + private def sbtScalafixVersionJson = s"""|{ | "updatedAt" : 9999999999999, From 8f1e56cb83030605fb9e146f182bd12cb93ad886 Mon Sep 17 00:00:00 2001 From: David Gregory <2992938+DavidGregory084@users.noreply.github.com> Date: Mon, 31 Jul 2023 14:52:27 +0100 Subject: [PATCH 2/3] Extract the common bits of runSourcesMigration and runBuildMigration into runSbtScalafix --- .../core/buildtool/sbt/SbtAlg.scala | 87 ++++++++++--------- .../core/buildtool/sbt/SbtAlgTest.scala | 12 +-- 2 files changed, 53 insertions(+), 46 deletions(-) diff --git a/modules/core/src/main/scala/org/scalasteward/core/buildtool/sbt/SbtAlg.scala b/modules/core/src/main/scala/org/scalasteward/core/buildtool/sbt/SbtAlg.scala index aa63728e4f..e6556f15a0 100644 --- a/modules/core/src/main/scala/org/scalasteward/core/buildtool/sbt/SbtAlg.scala +++ b/modules/core/src/main/scala/org/scalasteward/core/buildtool/sbt/SbtAlg.scala @@ -17,7 +17,7 @@ package org.scalasteward.core.buildtool.sbt import better.files.File -import cats.data.OptionT +import cats.data.{NonEmptyList, OptionT} import cats.effect.{Concurrent, Resource} import cats.syntax.all._ import org.scalasteward.core.application.Config @@ -107,22 +107,17 @@ final class SbtAlg[F[_]](config: Config)(implicit } private def runSourcesMigration(buildRoot: BuildRoot, migration: ScalafixMigration): F[Unit] = - OptionT(latestSbtScalafixVersion).foreachF { pluginVersion => - workspaceAlg.buildRootDir(buildRoot).flatMap { buildRootDir => - val plugin = scalaStewardSbtScalafix(pluginVersion) - fileAlg.createTemporarily(buildRootDir / project, plugin).surround { - val withScalacOptions = migration.scalacOptions.fold(Resource.unit[F]) { opts => - val options = scalaStewardScalafixOptions(opts.toList) - fileAlg.createTemporarily(buildRootDir, options) - } - withScalacOptions.surround { - val scalafixCmds = migration.rewriteRules.map(rule => s"$scalafixAll $rule").toList - val slurpOptions = SlurpOptions.ignoreBufferOverflow - sbt(Nel(scalafixEnable, scalafixCmds), buildRootDir, slurpOptions).void - } - } - } - } + for { + buildRootDir <- workspaceAlg.buildRootDir(buildRoot) + _ <- runSbtScalafix(buildRootDir, migration, metaBuilds = 0, startDepth = 0) + } yield () + + private def runBuildMigration(buildRoot: BuildRoot, migration: ScalafixMigration): F[Unit] = + for { + buildRootDir <- workspaceAlg.buildRootDir(buildRoot) + metaBuilds <- metaBuildsCount(buildRootDir) + _ <- runSbtScalafix(buildRootDir, migration, metaBuilds, startDepth = 1) + } yield () private def latestSbtScalafixVersion: F[Option[Version]] = versionsCache @@ -132,48 +127,60 @@ final class SbtAlg[F[_]](config: Config)(implicit private def addScalafixPluginTemporarily( buildRootDir: File, pluginVersion: Version, - metaBuilds: Int + metaBuilds: Int, + startDepth: Int ): Resource[F, Unit] = { + val buildsDepth = metaBuilds + startDepth val plugin = scalaStewardSbtScalafix(pluginVersion) List - .iterate(buildRootDir / project / project, metaBuilds + 1)(_ / project) + .iterate(buildRootDir / project, buildsDepth + 1)(_ / project) + .drop(startDepth) .collectFold(fileAlg.createTemporarily(_, plugin)) } private def addScalacOptionsTemporarily( buildRootDir: File, scalacOptions: Option[Nel[String]], - metaBuilds: Int + metaBuilds: Int, + startDepth: Int ): Resource[F, Unit] = scalacOptions.fold(Resource.unit[F]) { opts => + val buildsDepth = metaBuilds + startDepth val options = scalaStewardScalafixOptions(opts.toList) List - .iterate(buildRootDir / project, metaBuilds + 1)(_ / project) + .iterate(buildRootDir, buildsDepth + 1)(_ / project) + .drop(startDepth) .collectFold(fileAlg.createTemporarily(_, options)) } - private def runBuildMigration(buildRoot: BuildRoot, migration: ScalafixMigration): F[Unit] = + private def runSbtScalafix( + buildRootDir: File, + migration: ScalafixMigration, + metaBuilds: Int, + startDepth: Int + ): F[Unit] = OptionT(latestSbtScalafixVersion).foreachF { pluginVersion => - for { - buildRootDir <- workspaceAlg.buildRootDir(buildRoot) - metaBuilds <- metaBuildsCount(buildRootDir) - _ <- addScalafixPluginTemporarily(buildRootDir, pluginVersion, metaBuilds).surround { - addScalacOptionsTemporarily(buildRootDir, migration.scalacOptions, metaBuilds).surround { - val scalafixCmds = migration.rewriteRules.map(rule => s"$scalafixAll $rule").toList - val slurpOptions = SlurpOptions.ignoreBufferOverflow - val commands = Nel.fromList( - List.fill(metaBuilds + 1)(List(reloadPlugins, scalafixEnable) ++ scalafixCmds).flatten - ) - commands.fold(F.unit) { cmds => - sbt( - cmds, - buildRootDir, - slurpOptions - ).void + addScalafixPluginTemporarily(buildRootDir, pluginVersion, metaBuilds, startDepth) + .surround { + addScalacOptionsTemporarily(buildRootDir, migration.scalacOptions, metaBuilds, startDepth) + .surround { + val scalafixCmds = migration.rewriteRules.map(rule => s"$scalafixAll $rule").toList + val slurpOptions = SlurpOptions.ignoreBufferOverflow + val buildsDepth = metaBuilds + startDepth + val scalafixCommands = scalafixEnable :: scalafixCmds + val commandLists = + (scalafixCommands :: List.fill(buildsDepth)(reloadPlugins :: scalafixCommands)) + .drop(startDepth) + val commands = NonEmptyList.fromList(commandLists.flatten) + commands.fold(F.unit) { cmds => + sbt( + cmds, + buildRootDir, + slurpOptions + ).void + } } - } } - } yield () } private def sbt( diff --git a/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/SbtAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/SbtAlgTest.scala index a22b7b064f..ea06c3feb1 100644 --- a/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/SbtAlgTest.scala +++ b/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/SbtAlgTest.scala @@ -144,11 +144,11 @@ class SbtAlgTest extends FunSuite { val state = sbtAlg.runMigration(buildRoot, migration).runS(initialState).unsafeRunSync() val expected = initialState.copy( trace = Vector( + Cmd("test", "-d", s"$repoDir/project"), Cmd( "read", s"$workspace/store/versions/v2/https/repo1.maven.org/maven2/ch/epfl/scala/sbt-scalafix_2.12_1.0/versions.json" ), - Cmd("test", "-d", s"$repoDir/project"), Cmd("write", s"$repoDir/project/project/scala-steward-sbt-scalafix.sbt"), Cmd.execSandboxed( repoDir, @@ -185,12 +185,12 @@ class SbtAlgTest extends FunSuite { val state = sbtAlg.runMigration(buildRoot, migration).runS(initialState).unsafeRunSync() val expected = initialState.copy( trace = Vector( + Cmd("test", "-d", s"$repoDir/project"), + Cmd("test", "-d", s"$repoDir/project/project"), Cmd( "read", s"$workspace/store/versions/v2/https/repo1.maven.org/maven2/ch/epfl/scala/sbt-scalafix_2.12_1.0/versions.json" ), - Cmd("test", "-d", s"$repoDir/project"), - Cmd("test", "-d", s"$repoDir/project/project"), Cmd("write", s"$repoDir/project/project/scala-steward-sbt-scalafix.sbt"), Cmd("write", s"$repoDir/project/project/project/scala-steward-sbt-scalafix.sbt"), Cmd.execSandboxed( @@ -230,11 +230,11 @@ class SbtAlgTest extends FunSuite { val state = sbtAlg.runMigration(buildRoot, migration).runS(initialState).unsafeRunSync() val expected = initialState.copy( trace = Vector( + Cmd("test", "-d", s"$repoDir/project"), Cmd( "read", s"$workspace/store/versions/v2/https/repo1.maven.org/maven2/ch/epfl/scala/sbt-scalafix_2.12_1.0/versions.json" ), - Cmd("test", "-d", s"$repoDir/project"), Cmd("write", s"$repoDir/project/project/scala-steward-sbt-scalafix.sbt"), Cmd("write", s"$repoDir/project/scala-steward-scalafix-options.sbt"), Cmd.execSandboxed( @@ -274,12 +274,12 @@ class SbtAlgTest extends FunSuite { val state = sbtAlg.runMigration(buildRoot, migration).runS(initialState).unsafeRunSync() val expected = initialState.copy( trace = Vector( + Cmd("test", "-d", s"$repoDir/project"), + Cmd("test", "-d", s"$repoDir/project/project"), Cmd( "read", s"$workspace/store/versions/v2/https/repo1.maven.org/maven2/ch/epfl/scala/sbt-scalafix_2.12_1.0/versions.json" ), - Cmd("test", "-d", s"$repoDir/project"), - Cmd("test", "-d", s"$repoDir/project/project"), Cmd("write", s"$repoDir/project/project/scala-steward-sbt-scalafix.sbt"), Cmd("write", s"$repoDir/project/project/project/scala-steward-sbt-scalafix.sbt"), Cmd("write", s"$repoDir/project/scala-steward-scalafix-options.sbt"), From be3c89a2f6eec9cd14fdb8009d3f7248edb54032 Mon Sep 17 00:00:00 2001 From: David Gregory <2992938+DavidGregory084@users.noreply.github.com> Date: Wed, 2 Aug 2023 13:33:24 +0100 Subject: [PATCH 3/3] Run syntactic build migrations with the Scalafix CLI --- .editorconfig | 5 ++ .../core/buildtool/sbt/SbtAlg.scala | 23 ++++++++- .../core/edit/scalafix/ScalafixCli.scala | 2 +- .../org/scalasteward/core/io/FileAlg.scala | 8 ++- .../core/buildtool/sbt/SbtAlgTest.scala | 51 ++++++++++++++++++- 5 files changed, 84 insertions(+), 5 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..7d5ab3f477 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,5 @@ +root = true + +[*.{scala,sbt}] +indent_size = 2 +indent_style = space \ No newline at end of file diff --git a/modules/core/src/main/scala/org/scalasteward/core/buildtool/sbt/SbtAlg.scala b/modules/core/src/main/scala/org/scalasteward/core/buildtool/sbt/SbtAlg.scala index e6556f15a0..1482031535 100644 --- a/modules/core/src/main/scala/org/scalasteward/core/buildtool/sbt/SbtAlg.scala +++ b/modules/core/src/main/scala/org/scalasteward/core/buildtool/sbt/SbtAlg.scala @@ -25,7 +25,7 @@ import org.scalasteward.core.buildtool.sbt.command._ import org.scalasteward.core.buildtool.{BuildRoot, BuildToolAlg} import org.scalasteward.core.coursier.VersionsCache import org.scalasteward.core.data.{Dependency, Scope, Version} -import org.scalasteward.core.edit.scalafix.ScalafixMigration +import org.scalasteward.core.edit.scalafix.{ScalafixCli, ScalafixMigration} import org.scalasteward.core.io.process.SlurpOptions import org.scalasteward.core.io.{FileAlg, FileData, ProcessAlg, WorkspaceAlg} import org.scalasteward.core.util.Nel @@ -34,6 +34,7 @@ import org.scalasteward.core.buildtool.sbt.scalaStewardSbtScalafix final class SbtAlg[F[_]](config: Config)(implicit fileAlg: FileAlg[F], processAlg: ProcessAlg[F], + scalafixCli: ScalafixCli[F], workspaceAlg: WorkspaceAlg[F], versionsCache: VersionsCache[F], F: Concurrent[F] @@ -116,9 +117,29 @@ final class SbtAlg[F[_]](config: Config)(implicit for { buildRootDir <- workspaceAlg.buildRootDir(buildRoot) metaBuilds <- metaBuildsCount(buildRootDir) + _ <- runSyntacticBuildMigrations(buildRootDir, migration) _ <- runSbtScalafix(buildRootDir, migration, metaBuilds, startDepth = 1) } yield () + private def runSyntacticBuildMigrations( + buildRootDir: File, + migration: ScalafixMigration + ): F[Unit] = { + val rootSbtFiles = + fileAlg.walk(buildRootDir, 1).filter(_.extension.contains(".sbt")) + + val metaBuildFiles = + fileAlg.walk(buildRootDir / project, 3).filter(_.extension.exists(Set(".sbt", ".scala"))) + + val allBuildFiles = (rootSbtFiles ++ metaBuildFiles).compile.toList + + allBuildFiles.flatMap { buildFiles => + Nel.fromList(buildFiles).fold(F.unit) { files => + scalafixCli.runMigration(buildRootDir, files, migration) + } + } + } + private def latestSbtScalafixVersion: F[Option[Version]] = versionsCache .getVersions(Scope(sbtScalafixDependency, List(config.defaultResolver)), None) diff --git a/modules/core/src/main/scala/org/scalasteward/core/edit/scalafix/ScalafixCli.scala b/modules/core/src/main/scala/org/scalasteward/core/edit/scalafix/ScalafixCli.scala index 8a18e03fe8..6af0f4618e 100644 --- a/modules/core/src/main/scala/org/scalasteward/core/edit/scalafix/ScalafixCli.scala +++ b/modules/core/src/main/scala/org/scalasteward/core/edit/scalafix/ScalafixCli.scala @@ -31,7 +31,7 @@ final class ScalafixCli[F[_]](implicit ) { def runMigration(workingDir: File, files: Nel[File], migration: ScalafixMigration): F[Unit] = { val rules = migration.rewriteRules.map("--rules=" + _) - val cmd = scalafixBinary :: rules ::: files.map(_.pathAsString) + val cmd = scalafixBinary :: "--syntactic" :: rules ::: files.map(_.pathAsString) processAlg.exec(cmd, workingDir, slurpOptions = SlurpOptions.ignoreBufferOverflow).void } diff --git a/modules/core/src/main/scala/org/scalasteward/core/io/FileAlg.scala b/modules/core/src/main/scala/org/scalasteward/core/io/FileAlg.scala index d6d4179bcc..f6c44bd1c1 100644 --- a/modules/core/src/main/scala/org/scalasteward/core/io/FileAlg.scala +++ b/modules/core/src/main/scala/org/scalasteward/core/io/FileAlg.scala @@ -136,7 +136,13 @@ object FileAlg { Resource.fromAutoCloseable(source).use(src => F.blocking(src.mkString)) override def walk(dir: File, maxDepth: Int): Stream[F, File] = - Stream.eval(F.delay(dir.walk(maxDepth))).flatMap(Stream.fromBlockingIterator(_, 1)) + Stream.force( + F.blocking(dir.exists) + .ifF( + Stream.eval(F.delay(dir.walk(maxDepth))).flatMap(Stream.fromBlockingIterator(_, 1)), + Stream.empty.covary[F] + ) + ) override def writeFile(file: File, content: String): F[Unit] = logger.debug(s"Write $file") >> diff --git a/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/SbtAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/SbtAlgTest.scala index ea06c3feb1..eef7485c8c 100644 --- a/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/SbtAlgTest.scala +++ b/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/SbtAlgTest.scala @@ -6,6 +6,7 @@ import org.scalasteward.core.buildtool.BuildRoot import org.scalasteward.core.buildtool.sbt.command._ import org.scalasteward.core.data.{GroupId, Repo, Version} import org.scalasteward.core.edit.scalafix.ScalafixMigration +import org.scalasteward.core.edit.scalafix.ScalafixCli._ import org.scalasteward.core.mock.MockContext.context._ import org.scalasteward.core.mock.MockState import org.scalasteward.core.mock.MockState.TraceEntry.Cmd @@ -138,6 +139,7 @@ class SbtAlgTest extends FunSuite { ) val initialState = MockState.empty .addFiles( + repoDir / "build.sbt" -> "", workspace / s"store/versions/v2/https/repo1.maven.org/maven2/ch/epfl/scala/sbt-scalafix_2.12_1.0/versions.json" -> sbtScalafixVersionJson ) .unsafeRunSync() @@ -145,6 +147,15 @@ class SbtAlgTest extends FunSuite { val expected = initialState.copy( trace = Vector( Cmd("test", "-d", s"$repoDir/project"), + Cmd( + "VAR1=val1", + "VAR2=val2", + repoDir.pathAsString, + scalafixBinary, + "--syntactic", + "--rules=github:typelevel/sbt-tpolecat/v0_5?sha=v0.5.0", + s"$repoDir/build.sbt" + ), Cmd( "read", s"$workspace/store/versions/v2/https/repo1.maven.org/maven2/ch/epfl/scala/sbt-scalafix_2.12_1.0/versions.json" @@ -178,7 +189,9 @@ class SbtAlgTest extends FunSuite { ) val initialState = MockState.empty .addFiles( - repoDir / "project" / "Dependencies.scala" -> "object Dependencies", // put anything at all into the meta-build + repoDir / "build.sbt" -> "", + repoDir / "project" / "plugins.sbt" -> "", + repoDir / "project" / "Dependencies.scala" -> "object Dependencies", workspace / s"store/versions/v2/https/repo1.maven.org/maven2/ch/epfl/scala/sbt-scalafix_2.12_1.0/versions.json" -> sbtScalafixVersionJson ) .unsafeRunSync() @@ -187,6 +200,17 @@ class SbtAlgTest extends FunSuite { trace = Vector( Cmd("test", "-d", s"$repoDir/project"), Cmd("test", "-d", s"$repoDir/project/project"), + Cmd( + "VAR1=val1", + "VAR2=val2", + repoDir.pathAsString, + scalafixBinary, + "--syntactic", + "--rules=github:typelevel/sbt-tpolecat/v0_5?sha=v0.5.0", + s"$repoDir/build.sbt", + s"$repoDir/project/Dependencies.scala", + s"$repoDir/project/plugins.sbt" + ), Cmd( "read", s"$workspace/store/versions/v2/https/repo1.maven.org/maven2/ch/epfl/scala/sbt-scalafix_2.12_1.0/versions.json" @@ -224,6 +248,7 @@ class SbtAlgTest extends FunSuite { ) val initialState = MockState.empty .addFiles( + repoDir / "build.sbt" -> "", workspace / s"store/versions/v2/https/repo1.maven.org/maven2/ch/epfl/scala/sbt-scalafix_2.12_1.0/versions.json" -> sbtScalafixVersionJson ) .unsafeRunSync() @@ -231,6 +256,15 @@ class SbtAlgTest extends FunSuite { val expected = initialState.copy( trace = Vector( Cmd("test", "-d", s"$repoDir/project"), + Cmd( + "VAR1=val1", + "VAR2=val2", + repoDir.pathAsString, + scalafixBinary, + "--syntactic", + "--rules=github:typelevel/sbt-tpolecat/v0_5?sha=v0.5.0", + s"$repoDir/build.sbt" + ), Cmd( "read", s"$workspace/store/versions/v2/https/repo1.maven.org/maven2/ch/epfl/scala/sbt-scalafix_2.12_1.0/versions.json" @@ -267,7 +301,9 @@ class SbtAlgTest extends FunSuite { ) val initialState = MockState.empty .addFiles( - repoDir / "project" / "Dependencies.scala" -> "object Dependencies", // put anything at all into the meta-build + repoDir / "build.sbt" -> "", + repoDir / "project" / "plugins.sbt" -> "", + repoDir / "project" / "Dependencies.scala" -> "object Dependencies", workspace / s"store/versions/v2/https/repo1.maven.org/maven2/ch/epfl/scala/sbt-scalafix_2.12_1.0/versions.json" -> sbtScalafixVersionJson ) .unsafeRunSync() @@ -276,6 +312,17 @@ class SbtAlgTest extends FunSuite { trace = Vector( Cmd("test", "-d", s"$repoDir/project"), Cmd("test", "-d", s"$repoDir/project/project"), + Cmd( + "VAR1=val1", + "VAR2=val2", + repoDir.pathAsString, + scalafixBinary, + "--syntactic", + "--rules=github:typelevel/sbt-tpolecat/v0_5?sha=v0.5.0", + s"$repoDir/build.sbt", + s"$repoDir/project/Dependencies.scala", + s"$repoDir/project/plugins.sbt" + ), Cmd( "read", s"$workspace/store/versions/v2/https/repo1.maven.org/maven2/ch/epfl/scala/sbt-scalafix_2.12_1.0/versions.json"