Repository: scala-steward-org/scala-steward
Pull request #1584 (2020-08-31 21:15:25)

Allow setting compiler options for Scalafix migrations
In anticipation to https://github.com/typelevel/cats/pull/3566

codecov[bot]: # [Codecov](https://codecov.io/gh/scala-steward-org/scala-steward/pull/1584?src=pr&el=h1) Report
> Merging [#1584](https://codecov.io/gh/scala-steward-org/scala-steward/pull/1584?src=pr&el=desc) into [master](https://codecov.io/gh/scala-steward-org/scala-steward/commit/33249b1f3d16a2bad9568d5a634316e2f2379b98?el=desc) will **decrease** coverage by `0.01%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/scala-steward-org/scala-steward/pull/1584/graphs/tree.svg?width=650&height=150&src=pr&token=udzMsc1Dne)](https://codecov.io/gh/scala-steward-org/scala-steward/pull/1584?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master    #1584      +/-   ##
==========================================
- Coverage   70.26%   70.25%   -0.02%     
==========================================
  Files         113      113              
  Lines        1786     1785       -1     
  Branches       51       52       +1     
==========================================
- Hits         1255     1254       -1     
  Misses        531      531              
```


| [Impacted Files](https://codecov.io/gh/scala-steward-org/scala-steward/pull/1584?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [...ala/org/scalasteward/core/scalafix/Migration.scala](https://codecov.io/gh/scala-steward-org/scala-steward/pull/1584/diff?src=pr&el=tree#diff-bW9kdWxlcy9jb3JlL3NyYy9tYWluL3NjYWxhL29yZy9zY2FsYXN0ZXdhcmQvY29yZS9zY2FsYWZpeC9NaWdyYXRpb24uc2NhbGE=) | `100.00% <ø> (ø)` | |
| [...a/org/scalasteward/core/buildtool/sbt/SbtAlg.scala](https://codecov.io/gh/scala-steward-org/scala-steward/pull/1584/diff?src=pr&el=tree#diff-bW9kdWxlcy9jb3JlL3NyYy9tYWluL3NjYWxhL29yZy9zY2FsYXN0ZXdhcmQvY29yZS9idWlsZHRvb2wvc2J0L1NidEFsZy5zY2FsYQ==) | `92.59% <100.00%> (-0.75%)` | :arrow_down: |
| [.../org/scalasteward/core/buildtool/sbt/package.scala](https://codecov.io/gh/scala-steward-org/scala-steward/pull/1584/diff?src=pr&el=tree#diff-bW9kdWxlcy9jb3JlL3NyYy9tYWluL3NjYWxhL29yZy9zY2FsYXN0ZXdhcmQvY29yZS9idWlsZHRvb2wvc2J0L3BhY2thZ2Uuc2NhbGE=) | `92.85% <100.00%> (+1.19%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/scala-steward-org/scala-steward/pull/1584?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/scala-steward-org/scala-steward/pull/1584?src=pr&el=footer). Last update [33249b1...3b6a211](https://codecov.io/gh/scala-steward-org/scala-steward/pull/1584?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/build.sbt b/build.sbt
index ef10d533..bd248ff9 100644
--- a/build.sbt
+++ b/build.sbt
@@ -35,6 +35,7 @@ lazy val core = myCrossProject("core")
       Dependencies.attoCore,
       Dependencies.betterFiles,
       Dependencies.caseApp,
+      Dependencies.catsCore,
       Dependencies.catsEffect,
       Dependencies.circeConfig,
       Dependencies.circeGeneric,
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 7c857aff..6b58f697 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
@@ -87,14 +87,18 @@ object SbtAlg {
 
       override def runMigrations(repo: Repo, migrations: Nel[Migration]): F[Unit] =
         addGlobalPluginTemporarily(scalaStewardScalafixSbt) {
-          for {
-            repoDir <- workspaceAlg.repoDir(repo)
-            scalafixCmds = for {
-              migration <- migrations
-              rule <- migration.rewriteRules
-            } yield s"$scalafixAll $rule"
-            _ <- exec(sbtCmd(scalafixEnable :: scalafixCmds.toList), repoDir)
-          } yield ()
+          workspaceAlg.repoDir(repo).flatMap { repoDir =>
+            migrations.traverse_ { migration =>
+              val withScalacOptions =
+                migration.scalacOptions.fold[F[Unit] => F[Unit]](identity) { opts =>
+                  val file = scalaStewardScalafixOptions(opts.toList)
+                  fileAlg.createTemporarily(repoDir / file.name, file.content)(_)
+                }
+
+              val scalafixCmds = migration.rewriteRules.map(rule => s"$scalafixAll $rule").toList
+              withScalacOptions(exec(sbtCmd(scalafixEnable :: scalafixCmds), repoDir).void)
+            }
+          }
         }
 
       val sbtDir: F[File] =
diff --git a/modules/core/src/main/scala/org/scalasteward/core/buildtool/sbt/package.scala b/modules/core/src/main/scala/org/scalasteward/core/buildtool/sbt/package.scala
index 6b3df03e..f43798a6 100644
--- a/modules/core/src/main/scala/org/scalasteward/core/buildtool/sbt/package.scala
+++ b/modules/core/src/main/scala/org/scalasteward/core/buildtool/sbt/package.scala
@@ -28,16 +28,9 @@ package object sbt {
     org.scalasteward.core.BuildInfo.scalaBinaryVersion
 
   def sbtDependency(sbtVersion: SbtVersion): Option[Dependency] =
-    if (sbtVersion.toVersion >= Version("1.0.0"))
-      Some(
-        Dependency(
-          GroupId("org.scala-sbt"),
-          ArtifactId("sbt"),
-          sbtVersion.value
-        )
-      )
-    else
-      None
+    Option.when(sbtVersion.toVersion >= Version("1.0.0")) {
+      Dependency(GroupId("org.scala-sbt"), ArtifactId("sbt"), sbtVersion.value)
+    }
 
   val scalaStewardScalafixSbt: FileData =
     FileData(
@@ -45,6 +38,11 @@ package object sbt {
       """addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.19")"""
     )
 
+  def scalaStewardScalafixOptions(scalacOptions: List[String]): FileData = {
+    val args = scalacOptions.map(s => s""""$s"""").mkString(", ")
+    FileData("scala-steward-scalafix-options.sbt", s"ThisBuild / scalacOptions ++= List($args)")
+  }
+
   def stewardPlugin[F[_]](implicit fileAlg: FileAlg[F], F: Functor[F]): F[FileData] = {
     val name = "StewardPlugin.scala"
     fileAlg
diff --git a/modules/core/src/main/scala/org/scalasteward/core/scalafix/Migration.scala b/modules/core/src/main/scala/org/scalasteward/core/scalafix/Migration.scala
index d396bf26..f9064527 100644
--- a/modules/core/src/main/scala/org/scalasteward/core/scalafix/Migration.scala
+++ b/modules/core/src/main/scala/org/scalasteward/core/scalafix/Migration.scala
@@ -26,7 +26,8 @@ final case class Migration(
     artifactIds: Nel[String],
     newVersion: Version,
     rewriteRules: Nel[String],
-    doc: Option[String]
+    doc: Option[String],
+    scalacOptions: Option[Nel[String]]
 )
 
 object Migration {
diff --git a/project/Dependencies.scala b/project/Dependencies.scala
index c52bd6f8..042692f0 100644
--- a/project/Dependencies.scala
+++ b/project/Dependencies.scala
@@ -3,7 +3,7 @@ import sbt.Keys._
 
 object Dependencies {
   val mill = Def.setting {
-    val version = if (scalaBinaryVersion.value == "2.12") "0.6.3" else "0.8.0-5-1a410f"
+    val version = if (scalaBinaryVersion.value == "2.12") "0.6.3" else "0.8.0-6-bbbf19"
     "com.lihaoyi" %% "mill-scalalib" % version
   }
   val attoCore = "org.tpolecat" %% "atto-core" % "0.8.0"
@@ -11,7 +11,8 @@ object Dependencies {
   val betterMonadicFor = "com.olegpy" %% "better-monadic-for" % "0.3.1"
   val caseApp = "com.github.alexarchambault" %% "case-app" % "2.0.4"
   val catsEffect = "org.typelevel" %% "cats-effect" % "2.1.4"
-  val catsLaws = "org.typelevel" %% "cats-laws" % "2.1.1"
+  val catsCore = "org.typelevel" %% "cats-core" % "2.1.1"
+  val catsLaws = "org.typelevel" %% "cats-laws" % catsCore.revision
   val circeConfig = "io.circe" %% "circe-config" % "0.8.0"
   val circeGeneric = "io.circe" %% "circe-generic" % "0.13.0"
   val circeGenericExtras = "io.circe" %% "circe-generic-extras" % "0.13.0"


Test patch:
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 619fb49f..ee150e9a 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
@@ -63,6 +63,7 @@ class SbtAlgTest extends AnyFunSuite with Matchers {
         Nel.of("fs2-core"),
         Version("1.0.0"),
         Nel.of("github:functional-streams-for-scala/fs2/v1?sha=v1.0.5"),
+        None,
         None
       )
     )
@@ -88,4 +89,42 @@ class SbtAlgTest extends AnyFunSuite with Matchers {
       )
     )
   }
+
+  test("runMigrations: migration with scalacOptions") {
+    val repo = Repo("fthomas", "scala-steward")
+    val repoDir = config.workspace / repo.show
+    val migrations = Nel.of(
+      Migration(
+        GroupId("org.typelevel"),
+        Nel.of("cats-core"),
+        Version("2.2.0"),
+        Nel.of("github:cb372/cats/Cats_v2_2_0?sha=235bd7c92e431ab1902db174cf4665b05e08f2f1"),
+        None,
+        Some(Nel.of("-P:semanticdb:synthetics:on"))
+      )
+    )
+    val state = sbtAlg.runMigrations(repo, migrations).runS(MockState.empty).unsafeRunSync()
+
+    state shouldBe MockState.empty.copy(
+      commands = Vector(
+        List("write", "/tmp/steward/.sbt/0.13/plugins/scala-steward-scalafix.sbt"),
+        List("write", "/tmp/steward/.sbt/1.0/plugins/scala-steward-scalafix.sbt"),
+        List("write", s"$repoDir/scala-steward-scalafix-options.sbt"),
+        List(
+          "TEST_VAR=GREAT",
+          "ANOTHER_TEST_VAR=ALSO_GREAT",
+          repoDir.toString,
+          "firejail",
+          s"--whitelist=$repoDir",
+          "sbt",
+          "-batch",
+          "-no-colors",
+          s";$scalafixEnable;$scalafixAll github:cb372/cats/Cats_v2_2_0?sha=235bd7c92e431ab1902db174cf4665b05e08f2f1"
+        ),
+        List("rm", "-rf", s"$repoDir/scala-steward-scalafix-options.sbt"),
+        List("rm", "-rf", "/tmp/steward/.sbt/1.0/plugins/scala-steward-scalafix.sbt"),
+        List("rm", "-rf", "/tmp/steward/.sbt/0.13/plugins/scala-steward-scalafix.sbt")
+      )
+    )
+  }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/sbtTest.scala b/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/sbtTest.scala
new file mode 100644
index 00000000..d11ffbf2
--- /dev/null
+++ b/modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/sbtTest.scala
@@ -0,0 +1,11 @@
+package org.scalasteward.core.buildtool.sbt
+
+import org.scalatest.funsuite.AnyFunSuite
+import org.scalatest.matchers.should.Matchers
+
+class sbtTest extends AnyFunSuite with Matchers {
+  test("scalaStewardScalafixOptions") {
+    scalaStewardScalafixOptions(List("-P:semanticdb:synthetics:on")).content shouldBe
+      """ThisBuild / scalacOptions ++= List("-P:semanticdb:synthetics:on")"""
+  }
+}
diff --git a/modules/core/src/test/scala/org/scalasteward/core/github/http4s/authenticationTest.scala b/modules/core/src/test/scala/org/scalasteward/core/github/http4s/authenticationTest.scala
index 10fc2e3a..fe662b71 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/github/http4s/authenticationTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/github/http4s/authenticationTest.scala
@@ -10,8 +10,8 @@ import org.scalatest.matchers.should.Matchers
 class authenticationTest extends AnyFunSuite with Matchers {
   test("addCredentials") {
     val request = authentication
-      .addCredentials(AuthenticatedUser("user", "pass"))
-      .apply(Request[Id](headers = Headers.of(Accept(MediaType.text.plain))))
+      .addCredentials[Id](AuthenticatedUser("user", "pass"))
+      .apply(Request(headers = Headers.of(Accept(MediaType.text.plain))))
 
     request.headers shouldBe
       Headers.of(Accept(MediaType.text.plain), Authorization(BasicCredentials("user", "pass")))
diff --git a/modules/core/src/test/scala/org/scalasteward/core/scalafix/MigrationAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/scalafix/MigrationAlgTest.scala
index 6f48f292..d31db699 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/scalafix/MigrationAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/scalafix/MigrationAlgTest.scala
@@ -34,7 +34,8 @@ class MigrationAlgTest extends AnyFunSuite with Matchers {
           Nel.of("yumyum-.*"),
           Version("1.0.0"),
           Nel.of("awesome rewrite rule"),
-          Some("https://scalacenter.github.io/scalafix/")
+          Some("https://scalacenter.github.io/scalafix/"),
+          None
         )
       )
     )
@@ -61,6 +62,7 @@ class MigrationAlgTest extends AnyFunSuite with Matchers {
         Nel.of("yumyum-.*"),
         Version("1.0.0"),
         Nel.of("awesome rewrite rule"),
+        None,
         None
       )
     )
@@ -87,6 +89,6 @@ class MigrationAlgTest extends AnyFunSuite with Matchers {
   test("loadMigrations without extra file") {
     val migrations =
       MigrationAlg.loadMigrations[MockEff](None).runA(MockState.empty).unsafeRunSync()
-    migrations.size shouldBe 14
+    migrations.size should be > 1
   }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/vcs/data/NewPullRequestDataTest.scala b/modules/core/src/test/scala/org/scalasteward/core/vcs/data/NewPullRequestDataTest.scala
index 779cd80d..77f22842 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/vcs/data/NewPullRequestDataTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/vcs/data/NewPullRequestDataTest.scala
@@ -99,6 +99,7 @@ class NewPullRequestDataTest extends AnyFunSuite with Matchers {
       Nel.of(update.artifactId.name),
       Version("0.7.0"),
       Nel.of("I am a rewrite rule"),
+      None,
       None
     )
     val (label, appliedMigrations) = NewPullRequestData.migrationNote(List(migration))
@@ -120,7 +121,8 @@ class NewPullRequestDataTest extends AnyFunSuite with Matchers {
       Nel.of(update.artifactId.name),
       Version("0.7.0"),
       Nel.of("I am a rewrite rule"),
-      Some("https://scalacenter.github.io/scalafix/")
+      Some("https://scalacenter.github.io/scalafix/"),
+      None
     )
     val (label, appliedMigrations) = NewPullRequestData.migrationNote(List(migration))