Repository: scala-steward-org/scala-steward
Pull request #3097 (2023-06-21 10:59:23)

feat: add custom labels from repo config
Close https://github.com/scala-steward-org/scala-steward/issues/3048




Patch:
diff --git a/docs/repo-specific-configuration.md b/docs/repo-specific-configuration.md
index d480fdf0..f29ed690 100644
--- a/docs/repo-specific-configuration.md
+++ b/docs/repo-specific-configuration.md
@@ -73,11 +73,17 @@ pullRequests.grouping = [
   { name = "all", "title" = "Dependency updates", "filter" = [{"group" = "*"}] }
 ]
 
-# pullRequests.includeMatchedLabels allows to control which labels are added to PRs
+# pullRequests.includeMatchedLabels allows to control which autogenerated labels are added to PRs
+# This setting has no effect on custom labels (see below).
 # via a regex check each label is checked against.
 # Defaults to no regex (all labels are added) which is equivalent to ".*".
 pullRequests.includeMatchedLabels = "(.*semver.*)|(commit-count:n:.*)"
 
+# pullRequests.customLabels allows to add custom labels to PRs.
+# This is useful if you want to use the labels for automation (project board for example).
+# Defaults to no labels (no labels are added).
+pullRequests.customLabels = [ "dependencies", "scala" ]
+
 # Only these dependencies which match the given patterns are updated.
 #
 # Each pattern must have `groupId`, and may have `artifactId` and `version`.
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 1245d299..b6615e5a 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
@@ -317,9 +317,13 @@ object NewPullRequestData {
     val scalafixLabel = edits.collectFirst { case _: ScalafixEdit => "scalafix-migrations" }
     val oldVersionLabel = Option.when(filesWithOldVersion.nonEmpty)("old-version-remains")
 
-    updateTypeLabels(update) ++
-      semverLabels ++ List(scalafixLabel, oldVersionLabel).flatten ++
+    List.concat(
+      updateTypeLabels(update),
+      semverLabels,
+      scalafixLabel,
+      oldVersionLabel,
       List(commitCountLabel)
+    )
   }
 
   def filterLabels(labels: List[String], includeMatchedLabels: Option[Regex]): List[String] =
diff --git a/modules/core/src/main/scala/org/scalasteward/core/nurture/NurtureAlg.scala b/modules/core/src/main/scala/org/scalasteward/core/nurture/NurtureAlg.scala
index ff9aacc5..10301e07 100644
--- a/modules/core/src/main/scala/org/scalasteward/core/nurture/NurtureAlg.scala
+++ b/modules/core/src/main/scala/org/scalasteward/core/nurture/NurtureAlg.scala
@@ -241,7 +241,7 @@ final class NurtureAlg[F[_]](config: ForgeCfg)(implicit
         artifactIdToUpdateInfoUrls = artifactIdToUpdateInfoUrls.toMap,
         filesWithOldVersion = filesWithOldVersion,
         addLabels = config.addLabels,
-        labels = labels
+        labels = data.repoData.config.pullRequests.customLabels ++ labels
       )
     } yield requestData
 
diff --git a/modules/core/src/main/scala/org/scalasteward/core/repoconfig/PullRequestsConfig.scala b/modules/core/src/main/scala/org/scalasteward/core/repoconfig/PullRequestsConfig.scala
index a6764c28..39fef7b2 100644
--- a/modules/core/src/main/scala/org/scalasteward/core/repoconfig/PullRequestsConfig.scala
+++ b/modules/core/src/main/scala/org/scalasteward/core/repoconfig/PullRequestsConfig.scala
@@ -21,13 +21,15 @@ import cats.{Eq, Monoid}
 import io.circe.Codec
 import io.circe.generic.extras.Configuration
 import io.circe.generic.extras.semiauto.deriveConfiguredCodec
+
 import java.util.regex.PatternSyntaxException
 import scala.util.matching.Regex
 
 final case class PullRequestsConfig(
     frequency: Option[PullRequestFrequency] = None,
     grouping: List[PullRequestGroup] = Nil,
-    includeMatchedLabels: Option[Regex] = None
+    includeMatchedLabels: Option[Regex] = None,
+    customLabels: List[String] = Nil
 ) {
   def frequencyOrDefault: PullRequestFrequency =
     frequency.getOrElse(PullRequestsConfig.defaultFrequency)
@@ -57,7 +59,8 @@ object PullRequestsConfig {
         PullRequestsConfig(
           frequency = x.frequency.orElse(y.frequency),
           grouping = x.grouping |+| y.grouping,
-          includeMatchedLabels = x.includeMatchedLabels.orElse(y.includeMatchedLabels)
+          includeMatchedLabels = x.includeMatchedLabels.orElse(y.includeMatchedLabels),
+          customLabels = x.customLabels |+| y.customLabels
         )
     )
 }


Test patch:
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 5bc62da1..c0532143 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
@@ -11,7 +11,7 @@ import org.scalasteward.core.forge.data.NewPullRequestData
 import org.scalasteward.core.git.{Branch, Commit}
 import org.scalasteward.core.mock.MockContext.context
 import org.scalasteward.core.mock.{MockConfig, MockEff, MockState}
-import org.scalasteward.core.repoconfig.RepoConfig
+import org.scalasteward.core.repoconfig.{PullRequestsConfig, RepoConfig}
 
 class NurtureAlgTest extends CatsEffectSuite with Http4sDsl[MockEff] {
   test("preparePullRequest") {
@@ -123,4 +123,54 @@ 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)
+
+    val nurtureAlg = context.nurtureAlg
+    val dependency = "org.typelevel".g % ("cats-effect", "cats-effect_2.13").a % "3.3.0"
+    val customLabels = List("custom-label-1", "custom-label-2")
+    val repoData =
+      RepoData(
+        repo = Repo("scala-steward-org", "scala-steward"),
+        cache = dummyRepoCache,
+        config = RepoConfig(
+          pullRequests = PullRequestsConfig(
+            customLabels = customLabels
+          )
+        )
+      )
+    val update = (dependency %> "3.4.0").single
+    val baseBranch = Branch("main")
+    val updateBranch = Branch("update/cats-effect-3.4.0")
+    val updateData =
+      UpdateData(repoData, repoData.repo, update, baseBranch, dummySha1, updateBranch)
+    val edits = List(UpdateEdit(update, Commit(dummySha1)))
+    val state = MockState.empty.copy(clientResponses = HttpApp {
+      case HEAD -> Root / "typelevel" / "cats-effect"                                 => Ok()
+      case HEAD -> Root / "typelevel" / "cats-effect" / "releases" / "tag" / "v3.4.0" => Ok()
+      case HEAD -> Root / "typelevel" / "cats-effect" / "compare" / "v3.3.0...v3.4.0" => Ok()
+      case _                                                                          => NotFound()
+    })
+    nurtureAlg.preparePullRequest(updateData, edits).runA(state).map { obtained =>
+      assertEquals(
+        obtained.labels,
+        customLabels ++ List(
+          "library-update",
+          "early-semver-minor",
+          "semver-spec-minor",
+          "commit-count:1"
+        )
+      )
+
+      val nextToLastLine = nextToLast(obtained.body.split("\n"))
+
+      assertEquals(
+        nextToLastLine,
+        "labels: custom-label-1, custom-label-2, library-update, early-semver-minor, semver-spec-minor, commit-count:1"
+      )
+    }
+  }
 }