From 5301c190be57802ffb79143a202b4008fc179b4a Mon Sep 17 00:00:00 2001
From: Michael Mior <mmior@mail.rit.edu>
Date: Tue, 5 Nov 2024 14:10:43 -0500
Subject: [PATCH] Add JSON metadata in PRs

---
 .../core/forge/data/NewPullRequestData.scala  |  13 +-
 .../forge/data/NewPullRequestDataTest.scala   | 314 +++++++++++++++++-
 .../core/nurture/NurtureAlgTest.scala         |  48 ++-
 3 files changed, 359 insertions(+), 16 deletions(-)

diff --git a/modules/core/src/main/scala/org/scalasteward/core/forge/data/NewPullRequestData.scala b/modules/core/src/main/scala/org/scalasteward/core/forge/data/NewPullRequestData.scala
index b5b186a55b..4e659ac824 100644
--- a/modules/core/src/main/scala/org/scalasteward/core/forge/data/NewPullRequestData.scala
+++ b/modules/core/src/main/scala/org/scalasteward/core/forge/data/NewPullRequestData.scala
@@ -17,6 +17,8 @@
 package org.scalasteward.core.forge.data
 
 import cats.syntax.all._
+import io.circe.Json
+import io.circe.syntax._
 import org.http4s.Uri
 import org.scalasteward.core.data._
 import org.scalasteward.core.edit.EditAttempt
@@ -112,9 +114,18 @@ object NewPullRequestData {
         |<sup>
         |${labels.mkString("labels: ", ", ", "")}
         |</sup>
-        |""".stripMargin.trim
+        |
+        |<!-- scala-steward = ${metadataJson(update, labels)} -->""".stripMargin.trim
   }
 
+  def metadataJson(update: Update, labels: List[String]): String =
+    Json
+      .obj(
+        "Update" -> update.asJson,
+        "Labels" -> Json.fromValues(labels.map(_.asJson))
+      )
+      .toString
+
   def renderUpdateInfoUrls(updateInfoUrls: List[UpdateInfoUrl]): Option[String] =
     Option.when(updateInfoUrls.nonEmpty) {
       updateInfoUrls
diff --git a/modules/core/src/test/scala/org/scalasteward/core/forge/data/NewPullRequestDataTest.scala b/modules/core/src/test/scala/org/scalasteward/core/forge/data/NewPullRequestDataTest.scala
index ca72e2cb29..3ae0a0f50f 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/forge/data/NewPullRequestDataTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/forge/data/NewPullRequestDataTest.scala
@@ -60,7 +60,35 @@ class NewPullRequestDataTest extends FunSuite {
           |
           |<sup>
           |labels: library-update
-          |</sup>""".stripMargin
+          |</sup>
+          |
+          |<!-- scala-steward = {
+          |  "Update" : {
+          |    "ForArtifactId" : {
+          |      "crossDependency" : [
+          |        {
+          |          "groupId" : "ch.qos.logback",
+          |          "artifactId" : {
+          |            "name" : "logback-classic",
+          |            "maybeCrossName" : null
+          |          },
+          |          "version" : "1.2.0",
+          |          "sbtVersion" : null,
+          |          "scalaVersion" : null,
+          |          "configurations" : null
+          |        }
+          |      ],
+          |      "newerVersions" : [
+          |        "1.2.3"
+          |      ],
+          |      "newerGroupId" : null,
+          |      "newerArtifactId" : null
+          |    }
+          |  },
+          |  "Labels" : [
+          |    "library-update"
+          |  ]
+          |} -->""".stripMargin
 
     assertEquals(body, expected)
   }
@@ -127,7 +155,35 @@ class NewPullRequestDataTest extends FunSuite {
           |
           |<sup>
           |labels: library-update
-          |</sup>""".stripMargin
+          |</sup>
+          |
+          |<!-- scala-steward = {
+          |  "Update" : {
+          |    "ForArtifactId" : {
+          |      "crossDependency" : [
+          |        {
+          |          "groupId" : "ch.qos.logback",
+          |          "artifactId" : {
+          |            "name" : "logback-classic",
+          |            "maybeCrossName" : null
+          |          },
+          |          "version" : "1.2.0",
+          |          "sbtVersion" : null,
+          |          "scalaVersion" : null,
+          |          "configurations" : null
+          |        }
+          |      ],
+          |      "newerVersions" : [
+          |        "1.2.3"
+          |      ],
+          |      "newerGroupId" : null,
+          |      "newerArtifactId" : null
+          |    }
+          |  },
+          |  "Labels" : [
+          |    "library-update"
+          |  ]
+          |} -->""".stripMargin
 
     assertEquals(body, expected)
   }
@@ -191,7 +247,65 @@ class NewPullRequestDataTest extends FunSuite {
           |
           |<sup>
           |labels: library-update
-          |</sup>""".stripMargin
+          |</sup>
+          |
+          |<!-- scala-steward = {
+          |  "Update" : {
+          |    "Grouped" : {
+          |      "name" : "my-group",
+          |      "title" : "The PR title",
+          |      "updates" : [
+          |        {
+          |          "ForArtifactId" : {
+          |            "crossDependency" : [
+          |              {
+          |                "groupId" : "ch.qos.logback",
+          |                "artifactId" : {
+          |                  "name" : "logback-classic",
+          |                  "maybeCrossName" : null
+          |                },
+          |                "version" : "1.2.0",
+          |                "sbtVersion" : null,
+          |                "scalaVersion" : null,
+          |                "configurations" : null
+          |              }
+          |            ],
+          |            "newerVersions" : [
+          |              "1.2.3"
+          |            ],
+          |            "newerGroupId" : null,
+          |            "newerArtifactId" : null
+          |          }
+          |        },
+          |        {
+          |          "ForArtifactId" : {
+          |            "crossDependency" : [
+          |              {
+          |                "groupId" : "com.example",
+          |                "artifactId" : {
+          |                  "name" : "foo",
+          |                  "maybeCrossName" : null
+          |                },
+          |                "version" : "1.0.0",
+          |                "sbtVersion" : null,
+          |                "scalaVersion" : null,
+          |                "configurations" : null
+          |              }
+          |            ],
+          |            "newerVersions" : [
+          |              "2.0.0"
+          |            ],
+          |            "newerGroupId" : null,
+          |            "newerArtifactId" : null
+          |          }
+          |        }
+          |      ]
+          |    }
+          |  },
+          |  "Labels" : [
+          |    "library-update"
+          |  ]
+          |} -->""".stripMargin
 
     assertEquals(body, expected)
   }
@@ -248,7 +362,35 @@ class NewPullRequestDataTest extends FunSuite {
           |
           |<sup>
           |labels: library-update
-          |</sup>""".stripMargin
+          |</sup>
+          |
+          |<!-- scala-steward = {
+          |  "Update" : {
+          |    "ForArtifactId" : {
+          |      "crossDependency" : [
+          |        {
+          |          "groupId" : "ch.qos.logback",
+          |          "artifactId" : {
+          |            "name" : "logback-classic",
+          |            "maybeCrossName" : null
+          |          },
+          |          "version" : "1.2.0",
+          |          "sbtVersion" : null,
+          |          "scalaVersion" : null,
+          |          "configurations" : null
+          |        }
+          |      ],
+          |      "newerVersions" : [
+          |        "1.2.3"
+          |      ],
+          |      "newerGroupId" : null,
+          |      "newerArtifactId" : null
+          |    }
+          |  },
+          |  "Labels" : [
+          |    "library-update"
+          |  ]
+          |} -->""".stripMargin
 
     assertEquals(body, expected)
   }
@@ -642,7 +784,38 @@ class NewPullRequestDataTest extends FunSuite {
           |
           |<sup>
           |labels: library-update, early-semver-patch, semver-spec-patch, commit-count:0
-          |</sup>""".stripMargin
+          |</sup>
+          |
+          |<!-- scala-steward = {
+          |  "Update" : {
+          |    "ForArtifactId" : {
+          |      "crossDependency" : [
+          |        {
+          |          "groupId" : "ch.qos.logback",
+          |          "artifactId" : {
+          |            "name" : "logback-classic",
+          |            "maybeCrossName" : null
+          |          },
+          |          "version" : "1.2.0",
+          |          "sbtVersion" : null,
+          |          "scalaVersion" : null,
+          |          "configurations" : null
+          |        }
+          |      ],
+          |      "newerVersions" : [
+          |        "1.2.3"
+          |      ],
+          |      "newerGroupId" : null,
+          |      "newerArtifactId" : null
+          |    }
+          |  },
+          |  "Labels" : [
+          |    "library-update",
+          |    "early-semver-patch",
+          |    "semver-spec-patch",
+          |    "commit-count:0"
+          |  ]
+          |} -->""".stripMargin
 
     val expected = NewPullRequestData(
       title = "Update logback-classic to 1.2.3",
@@ -731,7 +904,70 @@ class NewPullRequestDataTest extends FunSuite {
           |
           |<sup>
           |labels: library-update, early-semver-patch, semver-spec-patch, early-semver-major, semver-spec-major, commit-count:0
-          |</sup>""".stripMargin
+          |</sup>
+          |
+          |<!-- scala-steward = {
+          |  "Update" : {
+          |    "Grouped" : {
+          |      "name" : "my-group",
+          |      "title" : null,
+          |      "updates" : [
+          |        {
+          |          "ForArtifactId" : {
+          |            "crossDependency" : [
+          |              {
+          |                "groupId" : "ch.qos.logback",
+          |                "artifactId" : {
+          |                  "name" : "logback-classic",
+          |                  "maybeCrossName" : null
+          |                },
+          |                "version" : "1.2.0",
+          |                "sbtVersion" : null,
+          |                "scalaVersion" : null,
+          |                "configurations" : null
+          |              }
+          |            ],
+          |            "newerVersions" : [
+          |              "1.2.3"
+          |            ],
+          |            "newerGroupId" : null,
+          |            "newerArtifactId" : null
+          |          }
+          |        },
+          |        {
+          |          "ForArtifactId" : {
+          |            "crossDependency" : [
+          |              {
+          |                "groupId" : "com.example",
+          |                "artifactId" : {
+          |                  "name" : "foo",
+          |                  "maybeCrossName" : null
+          |                },
+          |                "version" : "1.0.0",
+          |                "sbtVersion" : null,
+          |                "scalaVersion" : null,
+          |                "configurations" : null
+          |              }
+          |            ],
+          |            "newerVersions" : [
+          |              "2.0.0"
+          |            ],
+          |            "newerGroupId" : null,
+          |            "newerArtifactId" : null
+          |          }
+          |        }
+          |      ]
+          |    }
+          |  },
+          |  "Labels" : [
+          |    "library-update",
+          |    "early-semver-patch",
+          |    "semver-spec-patch",
+          |    "early-semver-major",
+          |    "semver-spec-major",
+          |    "commit-count:0"
+          |  ]
+          |} -->""".stripMargin
 
     val expected = NewPullRequestData(
       title = "Update for group my-group",
@@ -803,7 +1039,38 @@ class NewPullRequestDataTest extends FunSuite {
           |
           |<sup>
           |labels: library-update, early-semver-major, semver-spec-minor, commit-count:1
-          |</sup>""".stripMargin
+          |</sup>
+          |
+          |<!-- scala-steward = {
+          |  "Update" : {
+          |    "ForArtifactId" : {
+          |      "crossDependency" : [
+          |        {
+          |          "groupId" : "org.typelevel",
+          |          "artifactId" : {
+          |            "name" : "cats-effect",
+          |            "maybeCrossName" : null
+          |          },
+          |          "version" : "2.5.5",
+          |          "sbtVersion" : null,
+          |          "scalaVersion" : null,
+          |          "configurations" : null
+          |        }
+          |      ],
+          |      "newerVersions" : [
+          |        "3.4.2"
+          |      ],
+          |      "newerGroupId" : null,
+          |      "newerArtifactId" : null
+          |    }
+          |  },
+          |  "Labels" : [
+          |    "library-update",
+          |    "early-semver-major",
+          |    "semver-spec-minor",
+          |    "commit-count:1"
+          |  ]
+          |} -->""".stripMargin
 
     assertEquals(body, expected)
   }
@@ -857,7 +1124,38 @@ class NewPullRequestDataTest extends FunSuite {
           |
           |<sup>
           |labels: library-update, early-semver-major, semver-spec-minor, commit-count:1
-          |</sup>""".stripMargin
+          |</sup>
+          |
+          |<!-- scala-steward = {
+          |  "Update" : {
+          |    "ForArtifactId" : {
+          |      "crossDependency" : [
+          |        {
+          |          "groupId" : "com.lihaoyi",
+          |          "artifactId" : {
+          |            "name" : "os-lib",
+          |            "maybeCrossName" : null
+          |          },
+          |          "version" : "0.7.8",
+          |          "sbtVersion" : null,
+          |          "scalaVersion" : null,
+          |          "configurations" : null
+          |        }
+          |      ],
+          |      "newerVersions" : [
+          |        "0.9.1"
+          |      ],
+          |      "newerGroupId" : null,
+          |      "newerArtifactId" : null
+          |    }
+          |  },
+          |  "Labels" : [
+          |    "library-update",
+          |    "early-semver-major",
+          |    "semver-spec-minor",
+          |    "commit-count:1"
+          |  ]
+          |} -->""".stripMargin
 
     assertEquals(body, expected)
   }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/nurture/NurtureAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/nurture/NurtureAlgTest.scala
index c053214332..f03182c741 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/nurture/NurtureAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/nurture/NurtureAlgTest.scala
@@ -73,7 +73,39 @@ class NurtureAlgTest extends CatsEffectSuite with Http4sDsl[MockEff] {
              |
              |<sup>
              |labels: library-update, early-semver-minor, semver-spec-minor, version-scheme:early-semver, commit-count:1
-             |</sup>""".stripMargin.trim,
+             |</sup>
+             |
+             |<!-- scala-steward = {
+             |  "Update" : {
+             |    "ForArtifactId" : {
+             |      "crossDependency" : [
+             |        {
+             |          "groupId" : "org.typelevel",
+             |          "artifactId" : {
+             |            "name" : "cats-effect",
+             |            "maybeCrossName" : "cats-effect_2.13"
+             |          },
+             |          "version" : "3.3.0",
+             |          "sbtVersion" : null,
+             |          "scalaVersion" : null,
+             |          "configurations" : null
+             |        }
+             |      ],
+             |      "newerVersions" : [
+             |        "3.4.0"
+             |      ],
+             |      "newerGroupId" : null,
+             |      "newerArtifactId" : null
+             |    }
+             |  },
+             |  "Labels" : [
+             |    "library-update",
+             |    "early-semver-minor",
+             |    "semver-spec-minor",
+             |    "version-scheme:early-semver",
+             |    "commit-count:1"
+             |  ]
+             |} -->""".stripMargin.trim,
       head = "scala-steward:update/cats-effect-3.4.0",
       base = baseBranch,
       labels = List(
@@ -90,7 +122,8 @@ class NurtureAlgTest extends CatsEffectSuite with Http4sDsl[MockEff] {
   }
 
   test("preparePullRequest should not set labels if ForgeConfig.addLabels = false") {
-    def nextToLast(L: Array[String]) = L(L.size - 2)
+    def findLabelLine(L: Array[String]) =
+      L.zipWithIndex.find(_._1.contains("labels: ")).map(x => L(x._2)).getOrElse("")
 
     val config =
       MockConfig.config.copy(forgeCfg = MockConfig.config.forgeCfg.copy(addLabels = false))
@@ -116,9 +149,9 @@ class NurtureAlgTest extends CatsEffectSuite with Http4sDsl[MockEff] {
     })
     nurtureAlg.preparePullRequest(updateData, edits).runA(state).map { obtained =>
       assert(obtained.labels.isEmpty)
-      val nextToLastLine = nextToLast(obtained.body.split("\n"))
+      val labelLine = findLabelLine(obtained.body.split("\n"))
       assertEquals(
-        nextToLastLine,
+        labelLine,
         "labels: library-update, early-semver-minor, semver-spec-minor, version-scheme:early-semver, commit-count:1"
       )
     }
@@ -127,7 +160,8 @@ class NurtureAlgTest extends CatsEffectSuite with Http4sDsl[MockEff] {
   test(
     "preparePullRequest should set custom labels if PullRequestsConfig.customLabels is provided"
   ) {
-    def nextToLast(L: Array[String]) = L(L.size - 2)
+    def findLabelLine(L: Array[String]) =
+      L.zipWithIndex.find(_._1.contains("labels: ")).map(x => L(x._2)).getOrElse("")
 
     val nurtureAlg = context.nurtureAlg
     val dependency = "org.typelevel".g % ("cats-effect", "cats-effect_2.13").a % "3.3.0"
@@ -165,10 +199,10 @@ class NurtureAlgTest extends CatsEffectSuite with Http4sDsl[MockEff] {
         )
       )
 
-      val nextToLastLine = nextToLast(obtained.body.split("\n"))
+      val labelLine = findLabelLine(obtained.body.split("\n"))
 
       assertEquals(
-        nextToLastLine,
+        labelLine,
         "labels: custom-label-1, custom-label-2, library-update, early-semver-minor, semver-spec-minor, commit-count:1"
       )
     }