From c5589ffae2dc7ffaafcd3da383adc1287a022f64 Mon Sep 17 00:00:00 2001 From: "Frank S. Thomas" Date: Fri, 17 Nov 2023 07:39:17 +0100 Subject: [PATCH 1/2] Use `GitAlg.findFilesContaining` in `ScannerAlg` This implements the idea mentioned in https://github.com/scala-steward-org/scala-steward/pull/2994#issuecomment-1455174931 `ScannerAlg` now uses `GitAlg.findFilesContaining` instead of our own `FileAlg.findFiles` to find files that contain versions and groupIds. This simplifies `findPathsContaining` because we do not need the gitignore dependency anymore to skip files that are ignored by Git since `git grep`, which is used by `GitAlg.findFilesContaining`, does this automatically for us. The biggest impact of this change in the code base is in the tests. `EditAlgTest` and `RewriteTest` now need to actually execute `git grep` to find files that should be edited. For this, the `execCommands` flag is used (#3005) and Git repositories are created for these tests. One advantage of this change is that we mock less and the `MockState` traces are closer to what Steward is actually doing in production. --- .github/workflows/ci.yml | 4 + build.sbt | 3 +- .../core/edit/update/ScannerAlg.scala | 38 ++----- .../org/scalasteward/core/io/FileAlg.scala | 18 +--- .../buildtool/BuildToolDispatcherTest.scala | 18 +--- .../buildtool/scalacli/ScalaCliAlgTest.scala | 3 +- .../scalasteward/core/edit/EditAlgTest.scala | 99 ++++++++----------- .../scalasteward/core/edit/RewriteTest.scala | 3 +- .../core/edit/hooks/HookExecutorTest.scala | 46 +++------ .../scalasteward/core/mock/MockState.scala | 33 ++++++- project/Dependencies.scala | 1 - 11 files changed, 99 insertions(+), 167 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4379c5cfdb..5bf4927ff0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,6 +67,10 @@ jobs: - name: Check that workflows are up to date run: sbt githubWorkflowCheck + - uses: coursier/setup-action@v1 + with: + apps: scalafmt + - name: Build project run: sbt '++ ${{ matrix.scala }}' validate diff --git a/build.sbt b/build.sbt index 84ab340258..d8b1ddcca6 100644 --- a/build.sbt +++ b/build.sbt @@ -53,6 +53,8 @@ ThisBuild / githubWorkflowPublish := Seq( ThisBuild / githubWorkflowJavaVersions := Seq(JavaSpec(Temurin, "17"), JavaSpec(Temurin, "11")) ThisBuild / githubWorkflowBuild := Seq( + WorkflowStep + .Use(UseRef.Public("coursier", "setup-action", "v1"), params = Map("apps" -> "scalafmt")), WorkflowStep.Sbt(List("validate"), name = Some("Build project")), WorkflowStep.Use( UseRef.Public("codecov", "codecov-action", "v3"), @@ -122,7 +124,6 @@ lazy val core = myCrossProject("core") Dependencies.decline, Dependencies.fs2Core, Dependencies.fs2Io, - Dependencies.gitignore, Dependencies.http4sCirce, Dependencies.http4sClient, Dependencies.http4sCore, diff --git a/modules/core/src/main/scala/org/scalasteward/core/edit/update/ScannerAlg.scala b/modules/core/src/main/scala/org/scalasteward/core/edit/update/ScannerAlg.scala index 3c1d9aa5e5..8caef2659d 100644 --- a/modules/core/src/main/scala/org/scalasteward/core/edit/update/ScannerAlg.scala +++ b/modules/core/src/main/scala/org/scalasteward/core/edit/update/ScannerAlg.scala @@ -16,13 +16,12 @@ package org.scalasteward.core.edit.update -import better.files.File import cats.effect.Concurrent -import cats.syntax.functor._ -import com.github.arturopala.gitignore.GitIgnore +import cats.syntax.all._ import fs2.Stream import org.scalasteward.core.data.{Dependency, Repo, Version} import org.scalasteward.core.edit.update.data.{ModulePosition, VersionPosition} +import org.scalasteward.core.git.GitAlg import org.scalasteward.core.io.{FileAlg, FileData, WorkspaceAlg} import org.scalasteward.core.repoconfig.RepoConfig import org.scalasteward.core.util.Nel @@ -30,6 +29,7 @@ import org.scalasteward.core.util.Nel /** Scans all files that Scala Steward is allowed to edit for version and module positions. */ final class ScannerAlg[F[_]](implicit fileAlg: FileAlg[F], + gitAlg: GitAlg[F], workspaceAlg: WorkspaceAlg[F], F: Concurrent[F] ) { @@ -58,35 +58,15 @@ final class ScannerAlg[F[_]](implicit .compile .foldMonoid - private def getGitIgnore(repoDir: File): F[Option[GitIgnore]] = { - val gitIgnore = repoDir / ".gitignore" - fileAlg.readFile(gitIgnore).map(_.map(GitIgnore.parse)) - } - private def findPathsContaining( repo: Repo, config: RepoConfig, string: String - ): Stream[F, FileData] = { - def fileFilter(repoDir: File, maybeGitIgnore: Option[GitIgnore]) = (file: File) => { - val path = repoDir.relativize(file).toString - val notDotGit = !path.startsWith(".git/") - val onlyKeepConfiguredExtensions = - config.updates.fileExtensionsOrDefault.exists(path.endsWith) - val allowedByGitIgnore = maybeGitIgnore.map(_.isAllowed(path)).getOrElse(true) - val cond = notDotGit && - onlyKeepConfiguredExtensions && - allowedByGitIgnore - Option.when(cond)(path) + ): Stream[F, FileData] = + Stream.eval(workspaceAlg.repoDir(repo)).flatMap { repoDir => + Stream + .evalSeq(gitAlg.findFilesContaining(repo, string)) + .filter(path => config.updates.fileExtensionsOrDefault.exists(path.endsWith)) + .evalMapFilter(path => fileAlg.readFile(repoDir / path).map(_.map(FileData(path, _)))) } - val contentFilter = (content: String) => Some(content).filter(_.contains(string)) - - for { - repoDir <- Stream.eval(workspaceAlg.repoDir(repo)) - maybeRootGitIgnore <- Stream.eval(getGitIgnore(repoDir)) - files <- fileAlg - .findFiles(repoDir, fileFilter(repoDir, maybeRootGitIgnore), contentFilter) - .map(FileData.tupled) - } yield files - } } 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 78c967926d..1c845201f3 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 @@ -19,7 +19,7 @@ package org.scalasteward.core.io import better.files.File import cats.effect.{Resource, Sync} import cats.syntax.all._ -import cats.{ApplicativeError, Monad, MonadThrow} +import cats.{ApplicativeError, MonadThrow} import fs2.Stream import org.apache.commons.io.FileUtils import org.http4s.Uri @@ -67,22 +67,6 @@ trait FileAlg[F[_]] { readFile(file) .flatMap(_.fold(F.unit)(edit(_).flatMap(writeFile(file, _)))) .adaptError { case t => new Throwable(s"failed to edit $file", t) } - - final def findFiles[A, B]( - dir: File, - fileFilter: File => Option[A], - contentFilter: String => Option[B] - )(implicit F: Monad[F]): Stream[F, (A, B)] = { - val none = Option.empty[(A, B)].pure[F] - walk(dir).evalMapFilter { file => - isRegularFile(file).ifM( - fileFilter(file).fold(none) { a => - readFile(file).map(_.flatMap(contentFilter).tupleLeft(a)) - }, - none - ) - } - } } object FileAlg { diff --git a/modules/core/src/test/scala/org/scalasteward/core/buildtool/BuildToolDispatcherTest.scala b/modules/core/src/test/scala/org/scalasteward/core/buildtool/BuildToolDispatcherTest.scala index 897d852dc2..7e5f02a3b3 100644 --- a/modules/core/src/test/scala/org/scalasteward/core/buildtool/BuildToolDispatcherTest.scala +++ b/modules/core/src/test/scala/org/scalasteward/core/buildtool/BuildToolDispatcherTest.scala @@ -33,25 +33,11 @@ class BuildToolDispatcherTest extends FunSuite { Cmd("test", "-f", s"$repoDir/pom.xml"), Cmd("test", "-f", s"$repoDir/build.sc"), Cmd("test", "-f", s"$repoDir/build.sbt"), - Cmd.git( - repoDir, - "grep", - "-I", - "--fixed-strings", - "--files-with-matches", - "//> using lib " - ), + Cmd.gitGrep(repoDir, "//> using lib "), Cmd("test", "-f", s"$repoDir/mvn-build/pom.xml"), Cmd("test", "-f", s"$repoDir/mvn-build/build.sc"), Cmd("test", "-f", s"$repoDir/mvn-build/build.sbt"), - Cmd.git( - repoDir, - "grep", - "-I", - "--fixed-strings", - "--files-with-matches", - "//> using lib " - ), + Cmd.gitGrep(repoDir, "//> using lib "), Log("Get dependencies in . from sbt"), Cmd("read", s"$repoDir/project/build.properties"), Cmd("test", "-d", s"$repoDir/project"), diff --git a/modules/core/src/test/scala/org/scalasteward/core/buildtool/scalacli/ScalaCliAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/buildtool/scalacli/ScalaCliAlgTest.scala index 4841481f71..ca58a84e19 100644 --- a/modules/core/src/test/scala/org/scalasteward/core/buildtool/scalacli/ScalaCliAlgTest.scala +++ b/modules/core/src/test/scala/org/scalasteward/core/buildtool/scalacli/ScalaCliAlgTest.scala @@ -16,8 +16,7 @@ class ScalaCliAlgTest extends CatsEffectSuite { val buildRoot = BuildRoot(repo, ".") val repoDir = workspaceAlg.repoDir(repo).unsafeRunSync() val fileWithUsingLib = "test.md" // this test fails if the extension is .scala or .sc - val grepCmd = - Cmd.git(repoDir, "grep", "-I", "--fixed-strings", "--files-with-matches", "//> using lib ") + val grepCmd = Cmd.gitGrep(repoDir, "//> using lib ") val initial = MockState.empty.copy(commandOutputs = Map(grepCmd -> Right(List(fileWithUsingLib)))) val obtained = scalaCliAlg.containsBuild(buildRoot).runA(initial) diff --git a/modules/core/src/test/scala/org/scalasteward/core/edit/EditAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/edit/EditAlgTest.scala index 8052d7e934..1afe2ccc5d 100644 --- a/modules/core/src/test/scala/org/scalasteward/core/edit/EditAlgTest.scala +++ b/modules/core/src/test/scala/org/scalasteward/core/edit/EditAlgTest.scala @@ -1,6 +1,5 @@ package org.scalasteward.core.edit -import better.files.File import cats.effect.unsafe.implicits.global import munit.FunSuite import org.scalasteward.core.TestInstances.dummyRepoCache @@ -16,46 +15,39 @@ import org.scalasteward.core.scalafmt.ScalafmtAlg.opts import org.scalasteward.core.scalafmt.{scalafmtBinary, scalafmtConfName, scalafmtDependency} class EditAlgTest extends FunSuite { - private def gitStatus(repoDir: File): Cmd = - Cmd.git(repoDir, "status", "--porcelain", "--untracked-files=no", "--ignore-submodules") - test("applyUpdate") { val repo = Repo("edit-alg", "test-1") val data = RepoData(repo, dummyRepoCache, RepoConfig.empty) val repoDir = workspaceAlg.repoDir(repo).unsafeRunSync() val update = ("org.typelevel".g % "cats-core".a % "1.2.0" %> "1.3.0").single - val file1 = repoDir / "build.sbt" - val file2 = repoDir / "project/Dependencies.scala" + val buildSbt = repoDir / "build.sbt" + val scalaFile = repoDir / "project/Dependencies.scala" val gitignore = repoDir / ".gitignore" val state = MockState.empty - .addFiles(file1 -> """val catsVersion = "1.2.0"""", file2 -> "", gitignore -> "") + .copy(execCommands = true) + .initGitRepo( + repoDir, + buildSbt -> """val catsVersion = "1.2.0"""", + scalaFile -> "", + gitignore -> "" + ) .flatMap(editAlg.applyUpdate(data, update).runS) .unsafeRunSync() val expected = MockState.empty.copy( + execCommands = true, trace = Vector( - Cmd("read", gitignore.pathAsString), - Cmd("test", "-f", repoDir.pathAsString), - Cmd("test", "-f", gitignore.pathAsString), - Cmd("test", "-f", file1.pathAsString), - Cmd("read", file1.pathAsString), - Cmd("test", "-f", (repoDir / "project").pathAsString), - Cmd("test", "-f", file2.pathAsString), - Cmd("read", file2.pathAsString), - Cmd("read", gitignore.pathAsString), - Cmd("test", "-f", repoDir.pathAsString), - Cmd("test", "-f", gitignore.pathAsString), - Cmd("test", "-f", file1.pathAsString), - Cmd("read", file1.pathAsString), - Cmd("test", "-f", (repoDir / "project").pathAsString), - Cmd("test", "-f", file2.pathAsString), - Cmd("read", file2.pathAsString), - Cmd("read", file1.pathAsString), - Cmd("write", file1.pathAsString), - gitStatus(repoDir) + Cmd.gitGrep(repoDir, update.currentVersion.value), + Cmd("read", buildSbt.pathAsString), + Cmd.gitGrep(repoDir, update.groupId.value), + Cmd("read", buildSbt.pathAsString), + Cmd("write", buildSbt.pathAsString), + Cmd.gitStatus(repoDir), + Cmd.gitCommit(repoDir, "Update cats-core to 1.3.0"), + Cmd.gitLatestSha1(repoDir) ), - files = Map(file1 -> """val catsVersion = "1.3.0"""", file2 -> "", gitignore -> "") + files = Map(buildSbt -> """val catsVersion = "1.3.0"""", scalaFile -> "", gitignore -> "") ) assertEquals(state, expected) @@ -69,56 +61,41 @@ class EditAlgTest extends FunSuite { val data = RepoData(repo, cache, RepoConfig.empty) val repoDir = workspaceAlg.repoDir(repo).unsafeRunSync() val update = ("org.scalameta".g % "scalafmt-core".a % "2.0.0" %> "2.1.0").single - val gitignore = repoDir / ".gitignore" + val gitignore = (repoDir / ".gitignore") -> "target/" val scalafmtConf = repoDir / scalafmtConfName val scalafmtConfContent = """maxColumn = 100 |version = 2.0.0 |align.openParenCallSite = false |""".stripMargin - val buildSbt = repoDir / "build.sbt" + val buildSbt = (repoDir / "build.sbt") -> "\n" val target = repoDir / "target" // this file should not be read because it's under target which is git ignored - val targetScalaFile = target / "SomeFile.scala" + val targetScalaFile = (target / "SomeFile.scala") -> s"""object Test {"2.0.0"}""" val state = MockState.empty - .addFiles( - scalafmtConf -> scalafmtConfContent, - buildSbt -> "", - gitignore -> "target/", - targetScalaFile -> "" - ) + .copy(execCommands = true) + .initGitRepo(repoDir, scalafmtConf -> scalafmtConfContent, buildSbt, gitignore) + .flatMap(_.addFiles(targetScalaFile)) .flatMap(editAlg.applyUpdate(data, update).runS) .unsafeRunSync() val expected = MockState.empty.copy( + execCommands = true, trace = Vector( - Cmd("read", gitignore.pathAsString), - Cmd("test", "-f", repoDir.pathAsString), - Cmd("test", "-f", gitignore.pathAsString), - Cmd("test", "-f", scalafmtConf.pathAsString), + Cmd.gitGrep(repoDir, update.currentVersion.value), Cmd("read", scalafmtConf.pathAsString), - Cmd("test", "-f", buildSbt.pathAsString), - Cmd("read", buildSbt.pathAsString), - Cmd("test", "-f", target.pathAsString), - Cmd("test", "-f", targetScalaFile.pathAsString), - Cmd("read", gitignore.pathAsString), - Cmd("test", "-f", repoDir.pathAsString), - Cmd("test", "-f", gitignore.pathAsString), - Cmd("test", "-f", scalafmtConf.pathAsString), - Cmd("read", scalafmtConf.pathAsString), - Cmd("test", "-f", buildSbt.pathAsString), - Cmd("read", buildSbt.pathAsString), - Cmd("test", "-f", target.pathAsString), - Cmd("test", "-f", targetScalaFile.pathAsString), + Cmd.gitGrep(repoDir, update.groupId.value), Cmd("read", scalafmtConf.pathAsString), Cmd("write", scalafmtConf.pathAsString), Cmd.exec(repoDir, scalafmtBinary :: opts.nonInteractive :: opts.modeChanged: _*), - gitStatus(repoDir), + Cmd.gitStatus(repoDir), + Cmd.gitCommit(repoDir, "Update scalafmt-core to 2.1.0"), + Cmd.gitLatestSha1(repoDir), Log( "Executing post-update hook for org.scalameta:scalafmt-core with command 'scalafmt --non-interactive'" ), Cmd.exec(repoDir, scalafmtBinary, opts.nonInteractive), - gitStatus(repoDir) + Cmd.gitStatus(repoDir) ), files = Map( scalafmtConf -> @@ -126,9 +103,9 @@ class EditAlgTest extends FunSuite { |version = 2.1.0 |align.openParenCallSite = false |""".stripMargin, - buildSbt -> "", - gitignore -> "target/", - targetScalaFile -> "" + buildSbt, + gitignore, + targetScalaFile ) ) @@ -136,13 +113,15 @@ class EditAlgTest extends FunSuite { } test("applyUpdate with build Scalafix") { - val repo = Repo("edit-alg", "test-3-1") + val repo = Repo("edit-alg", "test-3") val data = RepoData(repo, dummyRepoCache, RepoConfig.empty) val repoDir = workspaceAlg.repoDir(repo).unsafeRunSync() val update = (sbtGroupId % sbtArtifactId % "1.4.9" %> "1.5.5").single val state = MockState.empty - .addFiles( + .copy(execCommands = true) + .initGitRepo( + repoDir, repoDir / "build.sbt" -> "", repoDir / "project" / "build.properties" -> """sbt.version=1.4.9""" ) diff --git a/modules/core/src/test/scala/org/scalasteward/core/edit/RewriteTest.scala b/modules/core/src/test/scala/org/scalasteward/core/edit/RewriteTest.scala index be14d2d44a..39107459d6 100644 --- a/modules/core/src/test/scala/org/scalasteward/core/edit/RewriteTest.scala +++ b/modules/core/src/test/scala/org/scalasteward/core/edit/RewriteTest.scala @@ -957,7 +957,8 @@ class RewriteTest extends FunSuite { val repoDir = workspaceAlg.repoDir(repo).unsafeRunSync() val filesInRepoDir = files.map { case (file, content) => repoDir / file -> content } val state = MockState.empty - .addFiles(filesInRepoDir.toSeq: _*) + .copy(execCommands = true) + .initGitRepo(repoDir, filesInRepoDir.toSeq: _*) .flatMap(editAlg.applyUpdate(data, update).runS) .unsafeRunSync() val obtained = state.files diff --git a/modules/core/src/test/scala/org/scalasteward/core/edit/hooks/HookExecutorTest.scala b/modules/core/src/test/scala/org/scalasteward/core/edit/hooks/HookExecutorTest.scala index 66fd8d0f7f..ab6539c436 100644 --- a/modules/core/src/test/scala/org/scalasteward/core/edit/hooks/HookExecutorTest.scala +++ b/modules/core/src/test/scala/org/scalasteward/core/edit/hooks/HookExecutorTest.scala @@ -29,7 +29,7 @@ class HookExecutorTest extends CatsEffectSuite { state.map(assertEquals(_, MockState.empty)) } - Seq(true, false).foreach { case blameRevIgnored => + Seq(true, false).foreach { blameRevIgnored => val isIgnored = if (blameRevIgnored) "ignored" else "not ignored" test(s"scalafmt: enabled by config / $gitBlameIgnoreRevsName $isIgnored") { @@ -37,11 +37,8 @@ class HookExecutorTest extends CatsEffectSuite { val update = (scalafmtGroupId % scalafmtArtifactId % "2.7.4" %> "2.7.5").single val initial = MockState.empty.copy(commandOutputs = Map( - Cmd - .git(repoDir, "status", "--porcelain", "--untracked-files=no", "--ignore-submodules") -> - Right(List("build.sbt")), - Cmd.git(repoDir, "rev-parse", "--verify", "HEAD") -> - Right(List(dummySha1.value.value)), + Cmd.gitStatus(repoDir) -> Right(List("build.sbt")), + Cmd.gitLatestSha1(repoDir) -> Right(List(dummySha1.value.value)), Cmd.git(repoDir, "check-ignore", gitBlameIgnoreRevs.pathAsString) -> (if (blameRevIgnored) Right(List.empty) else Left(dummyProcessError)) ) @@ -55,22 +52,12 @@ class HookExecutorTest extends CatsEffectSuite { else Vector( Cmd.git(repoDir, "add", gitBlameIgnoreRevs.pathAsString), - Cmd.git( + Cmd.gitStatus(repoDir), + Cmd.gitCommit( repoDir, - "status", - "--porcelain", - "--untracked-files=no", - "--ignore-submodules" - ), - Cmd.git( - repoDir, - "commit", - "--all", - "--no-gpg-sign", - "-m", s"Add 'Reformat with scalafmt 2.7.5' to $gitBlameIgnoreRevsName" ), - Cmd.git(repoDir, "rev-parse", "--verify", "HEAD") + Cmd.gitLatestSha1(repoDir) ) val traces = Vector( @@ -80,24 +67,13 @@ class HookExecutorTest extends CatsEffectSuite { Cmd( "VAR1=val1" :: "VAR2=val2" :: repoDir.toString :: scalafmtBinary :: opts.nonInteractive :: Nil ), - Cmd.git( - repoDir, - "status", - "--porcelain", - "--untracked-files=no", - "--ignore-submodules" - ), - Cmd.git( + Cmd.gitStatus(repoDir), + Cmd.gitCommit( repoDir, - "commit", - "--all", - "--no-gpg-sign", - "-m", "Reformat with scalafmt 2.7.5", - "-m", s"Executed command: $scalafmtBinary ${opts.nonInteractive}" ), - Cmd.git(repoDir, "rev-parse", "--verify", "HEAD"), + Cmd.gitLatestSha1(repoDir), Cmd("read", gitBlameIgnoreRevs.pathAsString), Cmd("write", gitBlameIgnoreRevs.pathAsString), Cmd.git(repoDir, "check-ignore", gitBlameIgnoreRevs.pathAsString) @@ -135,7 +111,7 @@ class HookExecutorTest extends CatsEffectSuite { "Executing post-update hook for com.codecommit:sbt-github-actions with command 'sbt githubWorkflowGenerate'" ), Cmd.execSandboxed(repoDir, "sbt", "githubWorkflowGenerate"), - Cmd.git(repoDir, "status", "--porcelain", "--untracked-files=no", "--ignore-submodules") + Cmd.gitStatus(repoDir) ) ) @@ -161,7 +137,7 @@ class HookExecutorTest extends CatsEffectSuite { trace = Vector( Log("Executing post-update hook for com.random:cool-lib with command 'sbt mySbtCommand'"), Cmd.execSandboxed(repoDir, "sbt", "mySbtCommand"), - Cmd.git(repoDir, "status", "--porcelain", "--untracked-files=no", "--ignore-submodules") + Cmd.gitStatus(repoDir) ) ) diff --git a/modules/core/src/test/scala/org/scalasteward/core/mock/MockState.scala b/modules/core/src/test/scala/org/scalasteward/core/mock/MockState.scala index cd0ec70c7c..d492dc120f 100644 --- a/modules/core/src/test/scala/org/scalasteward/core/mock/MockState.scala +++ b/modules/core/src/test/scala/org/scalasteward/core/mock/MockState.scala @@ -5,6 +5,7 @@ import cats.effect.{IO, Ref} import cats.syntax.all._ import org.http4s.{HttpApp, Uri} import org.scalasteward.core.git.FileGitAlg +import org.scalasteward.core.git.FileGitAlgTest.ioAuxGitAlg import org.scalasteward.core.io.FileAlgTest.ioFileAlg import org.scalasteward.core.mock.MockConfig.mockRoot import org.scalasteward.core.mock.MockState.TraceEntry @@ -26,6 +27,13 @@ final case class MockState( def addUris(newUris: (Uri, String)*): MockState = copy(uris = uris ++ newUris) + def initGitRepo(repoDir: File, files: (File, String)*): IO[MockState] = + for { + _ <- ioAuxGitAlg.createRepo(repoDir) + state <- addFiles(files: _*) + _ <- ioAuxGitAlg.addFiles(repoDir, files.map { case (file, _) => file }: _*) + } yield state + def rmFile(file: File): IO[MockState] = ioFileAlg.deleteForce(file).as(copy(files = files - file)) @@ -75,11 +83,26 @@ object MockState { ) ++ args ) - def git(repoDir: File, args: String*): Cmd = - Cmd( - List(s"GIT_ASKPASS=$mockRoot/askpass.sh", "VAR1=val1", "VAR2=val2", repoDir.toString) ++ - FileGitAlg.gitCmd.toList ++ args - ) + def git(repoDir: File, args: String*): Cmd = { + val env = + List(s"GIT_ASKPASS=$mockRoot/askpass.sh", "VAR1=val1", "VAR2=val2", repoDir.toString) + Cmd(env ++ FileGitAlg.gitCmd.toList ++ args) + } + + def gitCommit(repoDir: File, messages: String*): Cmd = { + val args = + "commit" :: "--all" :: "--no-gpg-sign" :: messages.toList.flatMap(m => List("-m", m)) + git(repoDir, args: _*) + } + + def gitGrep(repoDir: File, string: String): Cmd = + git(repoDir, "grep", "-I", "--fixed-strings", "--files-with-matches", string) + + def gitLatestSha1(repoDir: File): Cmd = + git(repoDir, "rev-parse", "--verify", "HEAD") + + def gitStatus(repoDir: File): Cmd = + git(repoDir, "status", "--porcelain", "--untracked-files=no", "--ignore-submodules") } final case class Log(log: (Option[Throwable], String)) extends TraceEntry diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 5d286f99ad..af18cf3170 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -22,7 +22,6 @@ object Dependencies { val disciplineMunit = "org.typelevel" %% "discipline-munit" % "1.0.9" val fs2Core = "co.fs2" %% "fs2-core" % "3.9.3" val fs2Io = "co.fs2" %% "fs2-io" % fs2Core.revision - val gitignore = "com.github.arturopala" %% "gitignore" % "0.6.0" val http4sCore = "org.http4s" %% "http4s-core" % "1.0.0-M40" val http4sCirce = "org.http4s" %% "http4s-circe" % http4sCore.revision val http4sClient = "org.http4s" %% "http4s-client" % http4sCore.revision From 68d374b1f3013228855e1cfd403279cf07fe13fe Mon Sep 17 00:00:00 2001 From: "Frank S. Thomas" Date: Fri, 17 Nov 2023 17:53:42 +0100 Subject: [PATCH 2/2] Observe changes done by scalafmt --- .../scalasteward/core/edit/EditAlgTest.scala | 6 ++--- .../scalasteward/core/io/MockProcessAlg.scala | 26 ++++++++++++++----- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/modules/core/src/test/scala/org/scalasteward/core/edit/EditAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/edit/EditAlgTest.scala index 1afe2ccc5d..fd806bd2fe 100644 --- a/modules/core/src/test/scala/org/scalasteward/core/edit/EditAlgTest.scala +++ b/modules/core/src/test/scala/org/scalasteward/core/edit/EditAlgTest.scala @@ -70,12 +70,12 @@ class EditAlgTest extends FunSuite { val buildSbt = (repoDir / "build.sbt") -> "\n" val target = repoDir / "target" // this file should not be read because it's under target which is git ignored - val targetScalaFile = (target / "SomeFile.scala") -> s"""object Test {"2.0.0"}""" + val targetScalaFile = target / "SomeFile.scala" val state = MockState.empty .copy(execCommands = true) .initGitRepo(repoDir, scalafmtConf -> scalafmtConfContent, buildSbt, gitignore) - .flatMap(_.addFiles(targetScalaFile)) + .flatMap(_.addFiles(targetScalaFile -> s""" object Test {"2.0.0"} """)) .flatMap(editAlg.applyUpdate(data, update).runS) .unsafeRunSync() @@ -105,7 +105,7 @@ class EditAlgTest extends FunSuite { |""".stripMargin, buildSbt, gitignore, - targetScalaFile + targetScalaFile -> s"""object Test { "2.0.0" }\n""" ) ) diff --git a/modules/core/src/test/scala/org/scalasteward/core/io/MockProcessAlg.scala b/modules/core/src/test/scala/org/scalasteward/core/io/MockProcessAlg.scala index f0a8dd073c..2223374579 100644 --- a/modules/core/src/test/scala/org/scalasteward/core/io/MockProcessAlg.scala +++ b/modules/core/src/test/scala/org/scalasteward/core/io/MockProcessAlg.scala @@ -1,5 +1,6 @@ package org.scalasteward.core.io +import cats.syntax.all._ import cats.data.Kleisli import cats.effect.IO import org.scalasteward.core.application.Config.ProcessCfg @@ -11,19 +12,30 @@ object MockProcessAlg { new ProcessAlg(config)({ args => Kleisli { ctx => for { - state <- ctx.get + state0 <- ctx.get cmd = Cmd( args.extraEnv.map { case (k, v) => s"$k=$v" } ++ args.workingDirectory.map(_.toString).toList ++ args.command.toList ) - _ <- ctx.set(state.appendTraceEntry(cmd)) - res <- state.commandOutputs.get(cmd) match { - case Some(output) => IO.fromEither(output) - case None if state.execCommands => ProcessAlgTest.ioProcessAlg.execImpl(args) - case None => IO.pure(List.empty) + state1 = state0.appendTraceEntry(cmd) + _ <- ctx.set(state1) + res <- state1.commandOutputs.get(cmd) match { + case Some(output) => IO.fromEither(output).tupleRight(state1.files) + case None if state1.execCommands => + for { + output <- ProcessAlgTest.ioProcessAlg.execImpl(args) + // External processes can modify tracked files. We read them again here so that + // they are in sync with the files in the filesystem. + files <- state1.files.keys.toList.traverse { file => + FileAlgTest.ioFileAlg.readFile(file).map(_.getOrElse("")).tupleLeft(file) + } + } yield (output, files.toMap) + case None => IO.pure((List.empty, state1.files)) } - } yield res + (output, files) = res + _ <- ctx.set(state1.copy(files = files)) + } yield output } }) }