Skip to content

Commit 57f91b2

Browse files
authored
Merge pull request #3215 from scala-steward-org/topic/use-git-grep-in-scanner
Use `GitAlg.findFilesContaining` in `ScannerAlg`
2 parents 1a9c3c1 + 5bfe93a commit 57f91b2

File tree

11 files changed

+115
-157
lines changed

11 files changed

+115
-157
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ jobs:
6767
- name: Check that workflows are up to date
6868
run: sbt githubWorkflowCheck
6969

70+
- uses: coursier/setup-action@v1
71+
with:
72+
apps: scalafmt
73+
7074
- name: Build project
7175
run: sbt '++ ${{ matrix.scala }}' validate
7276

build.sbt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ ThisBuild / githubWorkflowPublish := Seq(
5353
ThisBuild / githubWorkflowJavaVersions := Seq(JavaSpec(Temurin, "17"), JavaSpec(Temurin, "11"))
5454
ThisBuild / githubWorkflowBuild :=
5555
Seq(
56+
WorkflowStep
57+
.Use(UseRef.Public("coursier", "setup-action", "v1"), params = Map("apps" -> "scalafmt")),
5658
WorkflowStep.Sbt(List("validate"), name = Some("Build project")),
5759
WorkflowStep.Use(
5860
UseRef.Public("codecov", "codecov-action", "v3"),
@@ -122,7 +124,6 @@ lazy val core = myCrossProject("core")
122124
Dependencies.decline,
123125
Dependencies.fs2Core,
124126
Dependencies.fs2Io,
125-
Dependencies.gitignore,
126127
Dependencies.http4sCirce,
127128
Dependencies.http4sClient,
128129
Dependencies.http4sCore,

modules/core/src/main/scala/org/scalasteward/core/edit/update/ScannerAlg.scala

Lines changed: 9 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,20 @@
1616

1717
package org.scalasteward.core.edit.update
1818

19-
import better.files.File
2019
import cats.effect.Concurrent
21-
import cats.syntax.functor._
22-
import com.github.arturopala.gitignore.GitIgnore
20+
import cats.syntax.all._
2321
import fs2.Stream
2422
import org.scalasteward.core.data.{Dependency, Repo, Version}
2523
import org.scalasteward.core.edit.update.data.{ModulePosition, VersionPosition}
24+
import org.scalasteward.core.git.GitAlg
2625
import org.scalasteward.core.io.{FileAlg, FileData, WorkspaceAlg}
2726
import org.scalasteward.core.repoconfig.RepoConfig
2827
import org.scalasteward.core.util.Nel
2928

3029
/** Scans all files that Scala Steward is allowed to edit for version and module positions. */
3130
final class ScannerAlg[F[_]](implicit
3231
fileAlg: FileAlg[F],
32+
gitAlg: GitAlg[F],
3333
workspaceAlg: WorkspaceAlg[F],
3434
F: Concurrent[F]
3535
) {
@@ -58,35 +58,15 @@ final class ScannerAlg[F[_]](implicit
5858
.compile
5959
.foldMonoid
6060

61-
private def getGitIgnore(repoDir: File): F[Option[GitIgnore]] = {
62-
val gitIgnore = repoDir / ".gitignore"
63-
fileAlg.readFile(gitIgnore).map(_.map(GitIgnore.parse))
64-
}
65-
6661
private def findPathsContaining(
6762
repo: Repo,
6863
config: RepoConfig,
6964
string: String
70-
): Stream[F, FileData] = {
71-
def fileFilter(repoDir: File, maybeGitIgnore: Option[GitIgnore]) = (file: File) => {
72-
val path = repoDir.relativize(file).toString
73-
val notDotGit = !path.startsWith(".git/")
74-
val onlyKeepConfiguredExtensions =
75-
config.updates.fileExtensionsOrDefault.exists(path.endsWith)
76-
val allowedByGitIgnore = maybeGitIgnore.map(_.isAllowed(path)).getOrElse(true)
77-
val cond = notDotGit &&
78-
onlyKeepConfiguredExtensions &&
79-
allowedByGitIgnore
80-
Option.when(cond)(path)
65+
): Stream[F, FileData] =
66+
Stream.eval(workspaceAlg.repoDir(repo)).flatMap { repoDir =>
67+
Stream
68+
.evalSeq(gitAlg.findFilesContaining(repo, string))
69+
.filter(path => config.updates.fileExtensionsOrDefault.exists(path.endsWith))
70+
.evalMapFilter(path => fileAlg.readFile(repoDir / path).map(_.map(FileData(path, _))))
8171
}
82-
val contentFilter = (content: String) => Some(content).filter(_.contains(string))
83-
84-
for {
85-
repoDir <- Stream.eval(workspaceAlg.repoDir(repo))
86-
maybeRootGitIgnore <- Stream.eval(getGitIgnore(repoDir))
87-
files <- fileAlg
88-
.findFiles(repoDir, fileFilter(repoDir, maybeRootGitIgnore), contentFilter)
89-
.map(FileData.tupled)
90-
} yield files
91-
}
9272
}

modules/core/src/main/scala/org/scalasteward/core/io/FileAlg.scala

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ package org.scalasteward.core.io
1919
import better.files.File
2020
import cats.effect.{Resource, Sync}
2121
import cats.syntax.all._
22-
import cats.{ApplicativeError, Monad, MonadThrow}
22+
import cats.{ApplicativeError, MonadThrow}
2323
import fs2.Stream
2424
import org.apache.commons.io.FileUtils
2525
import org.http4s.Uri
@@ -67,22 +67,6 @@ trait FileAlg[F[_]] {
6767
readFile(file)
6868
.flatMap(_.fold(F.unit)(edit(_).flatMap(writeFile(file, _))))
6969
.adaptError { case t => new Throwable(s"failed to edit $file", t) }
70-
71-
final def findFiles[A, B](
72-
dir: File,
73-
fileFilter: File => Option[A],
74-
contentFilter: String => Option[B]
75-
)(implicit F: Monad[F]): Stream[F, (A, B)] = {
76-
val none = Option.empty[(A, B)].pure[F]
77-
walk(dir).evalMapFilter { file =>
78-
isRegularFile(file).ifM(
79-
fileFilter(file).fold(none) { a =>
80-
readFile(file).map(_.flatMap(contentFilter).tupleLeft(a))
81-
},
82-
none
83-
)
84-
}
85-
}
8670
}
8771

8872
object FileAlg {

modules/core/src/test/scala/org/scalasteward/core/buildtool/scalacli/ScalaCliAlgTest.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ class ScalaCliAlgTest extends CatsEffectSuite {
1818
val buildRoot = BuildRoot(repo, ".")
1919
val repoDir = workspaceAlg.repoDir(repo).unsafeRunSync()
2020
val fileWithUsingLib = "test.md" // this test fails if the extension is .scala or .sc
21-
val grepCmd =
22-
Cmd.git(repoDir, "grep", "-I", "--fixed-strings", "--files-with-matches", "//> using lib ")
21+
val grepCmd = Cmd.gitGrep(repoDir, "//> using lib ")
2322
val initial =
2423
MockState.empty.copy(commandOutputs = Map(grepCmd -> Right(List(fileWithUsingLib))))
2524
val obtained = scalaCliAlg.containsBuild(buildRoot).runA(initial)

modules/core/src/test/scala/org/scalasteward/core/edit/EditAlgTest.scala

Lines changed: 38 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package org.scalasteward.core.edit
22

3-
import better.files.File
43
import cats.effect.unsafe.implicits.global
54
import munit.FunSuite
65
import org.scalasteward.core.TestInstances.dummyRepoCache
@@ -16,46 +15,39 @@ import org.scalasteward.core.scalafmt.ScalafmtAlg.opts
1615
import org.scalasteward.core.scalafmt.{scalafmtBinary, scalafmtConfName, scalafmtDependency}
1716

1817
class EditAlgTest extends FunSuite {
19-
private def gitStatus(repoDir: File): Cmd =
20-
Cmd.git(repoDir, "status", "--porcelain", "--untracked-files=no", "--ignore-submodules")
21-
2218
test("applyUpdate") {
2319
val repo = Repo("edit-alg", "test-1")
2420
val data = RepoData(repo, dummyRepoCache, RepoConfig.empty)
2521
val repoDir = workspaceAlg.repoDir(repo).unsafeRunSync()
2622
val update = ("org.typelevel".g % "cats-core".a % "1.2.0" %> "1.3.0").single
27-
val file1 = repoDir / "build.sbt"
28-
val file2 = repoDir / "project/Dependencies.scala"
23+
val buildSbt = repoDir / "build.sbt"
24+
val scalaFile = repoDir / "project/Dependencies.scala"
2925
val gitignore = repoDir / ".gitignore"
3026

3127
val state = MockState.empty
32-
.addFiles(file1 -> """val catsVersion = "1.2.0"""", file2 -> "", gitignore -> "")
28+
.copy(execCommands = true)
29+
.initGitRepo(
30+
repoDir,
31+
buildSbt -> """val catsVersion = "1.2.0"""",
32+
scalaFile -> "",
33+
gitignore -> ""
34+
)
3335
.flatMap(editAlg.applyUpdate(data, update).runS)
3436
.unsafeRunSync()
3537

3638
val expected = MockState.empty.copy(
39+
execCommands = true,
3740
trace = Vector(
38-
Cmd("read", gitignore.pathAsString),
39-
Cmd("test", "-f", repoDir.pathAsString),
40-
Cmd("test", "-f", gitignore.pathAsString),
41-
Cmd("test", "-f", file1.pathAsString),
42-
Cmd("read", file1.pathAsString),
43-
Cmd("test", "-f", (repoDir / "project").pathAsString),
44-
Cmd("test", "-f", file2.pathAsString),
45-
Cmd("read", file2.pathAsString),
46-
Cmd("read", gitignore.pathAsString),
47-
Cmd("test", "-f", repoDir.pathAsString),
48-
Cmd("test", "-f", gitignore.pathAsString),
49-
Cmd("test", "-f", file1.pathAsString),
50-
Cmd("read", file1.pathAsString),
51-
Cmd("test", "-f", (repoDir / "project").pathAsString),
52-
Cmd("test", "-f", file2.pathAsString),
53-
Cmd("read", file2.pathAsString),
54-
Cmd("read", file1.pathAsString),
55-
Cmd("write", file1.pathAsString),
56-
gitStatus(repoDir)
41+
Cmd.gitGrep(repoDir, update.currentVersion.value),
42+
Cmd("read", buildSbt.pathAsString),
43+
Cmd.gitGrep(repoDir, update.groupId.value),
44+
Cmd("read", buildSbt.pathAsString),
45+
Cmd("write", buildSbt.pathAsString),
46+
Cmd.gitStatus(repoDir),
47+
Cmd.gitCommit(repoDir, "Update cats-core to 1.3.0"),
48+
Cmd.gitLatestSha1(repoDir)
5749
),
58-
files = Map(file1 -> """val catsVersion = "1.3.0"""", file2 -> "", gitignore -> "")
50+
files = Map(buildSbt -> """val catsVersion = "1.3.0"""", scalaFile -> "", gitignore -> "")
5951
)
6052

6153
assertEquals(state, expected)
@@ -69,80 +61,67 @@ class EditAlgTest extends FunSuite {
6961
val data = RepoData(repo, cache, RepoConfig.empty)
7062
val repoDir = workspaceAlg.repoDir(repo).unsafeRunSync()
7163
val update = ("org.scalameta".g % "scalafmt-core".a % "2.0.0" %> "2.1.0").single
72-
val gitignore = repoDir / ".gitignore"
64+
val gitignore = (repoDir / ".gitignore") -> "target/"
7365
val scalafmtConf = repoDir / scalafmtConfName
7466
val scalafmtConfContent = """maxColumn = 100
7567
|version = 2.0.0
7668
|align.openParenCallSite = false
7769
|""".stripMargin
78-
val buildSbt = repoDir / "build.sbt"
70+
val buildSbt = (repoDir / "build.sbt") -> "\n"
7971
val target = repoDir / "target"
8072
// this file should not be read because it's under target which is git ignored
8173
val targetScalaFile = target / "SomeFile.scala"
8274

8375
val state = MockState.empty
84-
.addFiles(
85-
scalafmtConf -> scalafmtConfContent,
86-
buildSbt -> "",
87-
gitignore -> "target/",
88-
targetScalaFile -> ""
89-
)
76+
.copy(execCommands = true)
77+
.initGitRepo(repoDir, scalafmtConf -> scalafmtConfContent, buildSbt, gitignore)
78+
.flatMap(_.addFiles(targetScalaFile -> s""" object Test {"2.0.0"} """))
9079
.flatMap(editAlg.applyUpdate(data, update).runS)
9180
.unsafeRunSync()
9281

9382
val expected = MockState.empty.copy(
83+
execCommands = true,
9484
trace = Vector(
95-
Cmd("read", gitignore.pathAsString),
96-
Cmd("test", "-f", repoDir.pathAsString),
97-
Cmd("test", "-f", gitignore.pathAsString),
98-
Cmd("test", "-f", scalafmtConf.pathAsString),
85+
Cmd.gitGrep(repoDir, update.currentVersion.value),
9986
Cmd("read", scalafmtConf.pathAsString),
100-
Cmd("test", "-f", buildSbt.pathAsString),
101-
Cmd("read", buildSbt.pathAsString),
102-
Cmd("test", "-f", target.pathAsString),
103-
Cmd("test", "-f", targetScalaFile.pathAsString),
104-
Cmd("read", gitignore.pathAsString),
105-
Cmd("test", "-f", repoDir.pathAsString),
106-
Cmd("test", "-f", gitignore.pathAsString),
107-
Cmd("test", "-f", scalafmtConf.pathAsString),
108-
Cmd("read", scalafmtConf.pathAsString),
109-
Cmd("test", "-f", buildSbt.pathAsString),
110-
Cmd("read", buildSbt.pathAsString),
111-
Cmd("test", "-f", target.pathAsString),
112-
Cmd("test", "-f", targetScalaFile.pathAsString),
87+
Cmd.gitGrep(repoDir, update.groupId.value),
11388
Cmd("read", scalafmtConf.pathAsString),
11489
Cmd("write", scalafmtConf.pathAsString),
11590
Cmd.exec(repoDir, scalafmtBinary :: opts.nonInteractive :: opts.modeChanged: _*),
116-
gitStatus(repoDir),
91+
Cmd.gitStatus(repoDir),
92+
Cmd.gitCommit(repoDir, "Update scalafmt-core to 2.1.0"),
93+
Cmd.gitLatestSha1(repoDir),
11794
Log(
11895
"Executing post-update hook for org.scalameta:scalafmt-core with command 'scalafmt --non-interactive'"
11996
),
12097
Cmd.exec(repoDir, scalafmtBinary, opts.nonInteractive),
121-
gitStatus(repoDir)
98+
Cmd.gitStatus(repoDir)
12299
),
123100
files = Map(
124101
scalafmtConf ->
125102
"""maxColumn = 100
126103
|version = 2.1.0
127104
|align.openParenCallSite = false
128105
|""".stripMargin,
129-
buildSbt -> "",
130-
gitignore -> "target/",
131-
targetScalaFile -> ""
106+
buildSbt,
107+
gitignore,
108+
targetScalaFile -> s"""object Test { "2.0.0" }\n"""
132109
)
133110
)
134111

135112
assertEquals(state, expected)
136113
}
137114

138115
test("applyUpdate with build Scalafix") {
139-
val repo = Repo("edit-alg", "test-3-1")
116+
val repo = Repo("edit-alg", "test-3")
140117
val data = RepoData(repo, dummyRepoCache, RepoConfig.empty)
141118
val repoDir = workspaceAlg.repoDir(repo).unsafeRunSync()
142119
val update = (sbtGroupId % sbtArtifactId % "1.4.9" %> "1.5.5").single
143120

144121
val state = MockState.empty
145-
.addFiles(
122+
.copy(execCommands = true)
123+
.initGitRepo(
124+
repoDir,
146125
repoDir / "build.sbt" -> "",
147126
repoDir / "project" / "build.properties" -> """sbt.version=1.4.9"""
148127
)

modules/core/src/test/scala/org/scalasteward/core/edit/RewriteTest.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,8 @@ class RewriteTest extends FunSuite {
957957
val repoDir = workspaceAlg.repoDir(repo).unsafeRunSync()
958958
val filesInRepoDir = files.map { case (file, content) => repoDir / file -> content }
959959
val state = MockState.empty
960-
.addFiles(filesInRepoDir.toSeq: _*)
960+
.copy(execCommands = true)
961+
.initGitRepo(repoDir, filesInRepoDir.toSeq: _*)
961962
.flatMap(editAlg.applyUpdate(data, update).runS)
962963
.unsafeRunSync()
963964
val obtained = state.files

0 commit comments

Comments
 (0)