Repository: scala-steward-org/scala-steward (scala)

Issue:
Note in PR body if a Scalafix migration does not produce changes
See https://github.com/typelevel/scalacheck-effect/pull/88.

Pull request description:
* indicate if a Scalafix migration produced no change
* group rules and documentation together
* add for which new version the migration got applied

fixes #2038

Below an example from a test case:

<details>
<summary>Applied Scalafix Migrations</summary>

* com.spotify:scio-core:0.7.0
  * I am a rewrite rule
  * I am a 2nd rewrite rule
  * Documentation: https://scalacenter.github.io/scalafix/
* org.typeleve:{cats-effect,cats-effect-laws}:3.0.0 (created no change)
  * I am a rule without an effect
</details>

Patch:
diff --git a/modules/core/src/main/scala/org/scalasteward/core/vcs/data/NewPullRequestData.scala b/modules/core/src/main/scala/org/scalasteward/core/vcs/data/NewPullRequestData.scala
index e525295819..759003743a 100644
--- a/modules/core/src/main/scala/org/scalasteward/core/vcs/data/NewPullRequestData.scala
+++ b/modules/core/src/main/scala/org/scalasteward/core/vcs/data/NewPullRequestData.scala
@@ -23,11 +23,10 @@ import org.http4s.Uri
 import org.scalasteward.core.data._
 import org.scalasteward.core.edit.EditAttempt
 import org.scalasteward.core.edit.EditAttempt.ScalafixEdit
-import org.scalasteward.core.edit.scalafix.ScalafixMigration
 import org.scalasteward.core.git
 import org.scalasteward.core.git.Branch
 import org.scalasteward.core.repoconfig.RepoConfigAlg
-import org.scalasteward.core.util.Details
+import org.scalasteward.core.util.{Details, Nel}
 
 final case class UpdateState(
     state: PullRequestState
@@ -56,7 +55,7 @@ object NewPullRequestData {
       filesWithOldVersion: List[String]
   ): String = {
     val artifacts = artifactsWithOptionalUrl(update, artifactIdToUrl)
-    val migrations = edits.collect { case ScalafixEdit(migration, _, _) => migration }
+    val migrations = edits.collect { case scalafixEdit: ScalafixEdit => scalafixEdit }
     val (migrationLabel, appliedMigrations) = migrationNote(migrations)
     val (oldVersionLabel, oldVersionDetails) = oldVersionNote(filesWithOldVersion, update)
     val details = appliedMigrations.toList ++
@@ -167,23 +166,31 @@ object NewPullRequestData {
           |""".stripMargin.trim
     )
 
-  def migrationNote(migrations: List[ScalafixMigration]): (Option[String], Option[Details]) =
-    if (migrations.isEmpty) (None, None)
+  def migrationNote(scalafixEdits: List[ScalafixEdit]): (Option[String], Option[Details]) =
+    if (scalafixEdits.isEmpty) (None, None)
     else {
-      val ruleList =
-        migrations.flatMap(_.rewriteRules.toList).map(rule => s"* $rule").mkString("\n")
-      val docList = migrations.flatMap(_.doc).map(uri => s"* $uri").mkString("\n")
-      val docSection =
-        if (docList.isEmpty)
-          ""
-        else
-          s"\n\nDocumentation:\n\n$docList"
+      val body = scalafixEdits
+        .map { scalafixEdit =>
+          val migration = scalafixEdit.migration
+          val listElements =
+            (migration.rewriteRules.map(rule => s"  * $rule").toList ++ migration.doc.map(uri =>
+              s"  * Documentation: $uri"
+            )).mkString("\n")
+          val artifactName = migration.artifactIds match {
+            case Nel(one, Nil) => one
+            case multiple      => multiple.toList.mkString("{", ",", "}")
+          }
+          val name = s"${migration.groupId.value}:${artifactName}:${migration.newVersion.value}"
+          val createdChange = scalafixEdit.maybeCommit.fold(" (created no change)")(_ => "")
+          s"* $name$createdChange\n$listElements"
+        }
+        .mkString("\n")
       (
         Some("scalafix-migrations"),
         Some(
           Details(
-            "Applied Migrations",
-            s"$ruleList$docSection"
+            "Applied Scalafix Migrations",
+            body
           )
         )
       )


Test patch:
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 f0a9dc295d..93e9b077fc 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
@@ -7,8 +7,9 @@ import org.scalasteward.core.TestInstances.dummyRepoCache
 import org.scalasteward.core.TestSyntax._
 import org.scalasteward.core.buildtool.sbt.data.SbtVersion
 import org.scalasteward.core.data._
+import org.scalasteward.core.edit.EditAttempt.ScalafixEdit
 import org.scalasteward.core.edit.scalafix.ScalafixMigration
-import org.scalasteward.core.git.{Branch, Sha1}
+import org.scalasteward.core.git.{Branch, Commit, Sha1}
 import org.scalasteward.core.repoconfig.RepoConfig
 import org.scalasteward.core.util.Nel
 
@@ -105,49 +106,98 @@ class NewPullRequestDataTest extends FunSuite {
   }
 
   test("migrationNote: when artifact has migrations") {
-    val update = Update.Single("com.spotify" % "scio-core" % "0.6.0", Nel.of("0.7.0"))
-    val migration = ScalafixMigration(
-      update.groupId,
-      Nel.of(update.artifactId.name),
-      Version("0.7.0"),
-      Nel.of("I am a rewrite rule")
+    val scalafixEdit = ScalafixEdit(
+      ScalafixMigration(
+        GroupId("com.spotify"),
+        Nel.one("scio-core"),
+        Version("0.7.0"),
+        Nel.of("I am a rewrite rule")
+      ),
+      Right(()),
+      Some(Commit())
     )
-    val (label, appliedMigrations) = NewPullRequestData.migrationNote(List(migration))
+    val (label, appliedMigrations) = NewPullRequestData.migrationNote(List(scalafixEdit))
 
     assertEquals(label, Some("scalafix-migrations"))
     assertEquals(
       appliedMigrations.fold("")(_.toHtml),
       """<details>
-        |<summary>Applied Migrations</summary>
+        |<summary>Applied Scalafix Migrations</summary>
         |
-        |* I am a rewrite rule
+        |* com.spotify:scio-core:0.7.0
+        |  * I am a rewrite rule
         |</details>
       """.stripMargin.trim
     )
   }
 
   test("migrationNote: when artifact has migrations with docs") {
-    val update = Update.Single("com.spotify" % "scio-core" % "0.6.0", Nel.of("0.7.0"))
-    val migration = ScalafixMigration(
-      update.groupId,
-      Nel.of(update.artifactId.name),
-      Version("0.7.0"),
-      Nel.of("I am a rewrite rule"),
-      Some("https://scalacenter.github.io/scalafix/")
+    val scalafixEdit = ScalafixEdit(
+      ScalafixMigration(
+        GroupId("com.spotify"),
+        Nel.one("scio-core"),
+        Version("0.7.0"),
+        Nel.of("I am a rewrite rule", "I am a 2nd rewrite rule"),
+        Some("https://scalacenter.github.io/scalafix/")
+      ),
+      Right(()),
+      Some(Commit())
     )
-    val (label, appliedMigrations) = NewPullRequestData.migrationNote(List(migration))
+    val (label, detail) = NewPullRequestData.migrationNote(List(scalafixEdit))
 
     assertEquals(label, Some("scalafix-migrations"))
     assertEquals(
-      appliedMigrations.fold("")(_.toHtml),
+      detail.fold("")(_.toHtml),
       """<details>
-        |<summary>Applied Migrations</summary>
+        |<summary>Applied Scalafix Migrations</summary>
         |
-        |* I am a rewrite rule
-        |
-        |Documentation:
+        |* com.spotify:scio-core:0.7.0
+        |  * I am a rewrite rule
+        |  * I am a 2nd rewrite rule
+        |  * Documentation: https://scalacenter.github.io/scalafix/
+        |</details>
+      """.stripMargin.trim
+    )
+  }
+
+  test("migrationNote: with 2 migrations where one didn't produce a change") {
+    val scalafixEdit1 = ScalafixEdit(
+      ScalafixMigration(
+        GroupId("com.spotify"),
+        Nel.one("scio-core"),
+        Version("0.7.0"),
+        Nel.of("I am a rewrite rule", "I am a 2nd rewrite rule"),
+        Some("https://scalacenter.github.io/scalafix/")
+      ),
+      Right(()),
+      Some(Commit())
+    )
+
+    val scalafixEdit2 = ScalafixEdit(
+      ScalafixMigration(
+        GroupId("org.typeleve"),
+        Nel.of("cats-effect", "cats-effect-laws"),
+        Version("3.0.0"),
+        Nel.of("I am a rule without an effect"),
+        None
+      ),
+      Right(()),
+      None
+    )
+    val (label, detail) = NewPullRequestData.migrationNote(List(scalafixEdit1, scalafixEdit2))
+
+    assertEquals(label, Some("scalafix-migrations"))
+    assertEquals(
+      detail.fold("")(_.toHtml),
+      """<details>
+        |<summary>Applied Scalafix Migrations</summary>
         |
-        |* https://scalacenter.github.io/scalafix/
+        |* com.spotify:scio-core:0.7.0
+        |  * I am a rewrite rule
+        |  * I am a 2nd rewrite rule
+        |  * Documentation: https://scalacenter.github.io/scalafix/
+        |* org.typeleve:{cats-effect,cats-effect-laws}:3.0.0 (created no change)
+        |  * I am a rule without an effect
         |</details>
       """.stripMargin.trim
     )