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

Issue:
Compare url & release notes/changelog are restricted to {github,gitlab}.com
Current logic of generating compare url and release notes/changelog are restricted to either github.com or gitlab.com
```
if (repoUrl.startsWith("https://github.com/") || repoUrl.startsWith("https://gitlab.com/"))
```

Is it possible to configure/extend this, so that git enterprise urls (such as git.enterprise.company.com) can also be included in this?

Pull request description:
Currently we have `github.com` and other urls hardcoded in the code, which makes it unusable in environments with different on-prem domain names.

Fixes #1088

Patch:
diff --git a/modules/core/src/main/scala/org/scalasteward/core/vcs/VCSExtraAlg.scala b/modules/core/src/main/scala/org/scalasteward/core/vcs/VCSExtraAlg.scala
index ebdca5f5a4..b11bfe850d 100644
--- a/modules/core/src/main/scala/org/scalasteward/core/vcs/VCSExtraAlg.scala
+++ b/modules/core/src/main/scala/org/scalasteward/core/vcs/VCSExtraAlg.scala
@@ -19,6 +19,7 @@ package org.scalasteward.core.vcs
 import cats.Monad
 import cats.syntax.all._
 import org.http4s.Uri
+import org.scalasteward.core.application.Config
 import org.scalasteward.core.data.{ReleaseRelatedUrl, Update}
 import org.scalasteward.core.util.HttpExistenceClient
 import org.scalasteward.core.vcs
@@ -30,13 +31,13 @@ trait VCSExtraAlg[F[_]] {
 object VCSExtraAlg {
   def create[F[_]](implicit
       existenceClient: HttpExistenceClient[F],
+      config: Config,
       F: Monad[F]
   ): VCSExtraAlg[F] =
     new VCSExtraAlg[F] {
       override def getReleaseRelatedUrls(repoUrl: Uri, update: Update): F[List[ReleaseRelatedUrl]] =
         vcs
-          .possibleReleaseRelatedUrls(repoUrl, update)
+          .possibleReleaseRelatedUrls(config.vcsType, config.vcsApiHost, repoUrl, update)
           .filterA(releaseRelatedUrl => existenceClient.exists(releaseRelatedUrl.url))
-
     }
 }
diff --git a/modules/core/src/main/scala/org/scalasteward/core/vcs/package.scala b/modules/core/src/main/scala/org/scalasteward/core/vcs/package.scala
index 1f54467dc8..6385c39155 100644
--- a/modules/core/src/main/scala/org/scalasteward/core/vcs/package.scala
+++ b/modules/core/src/main/scala/org/scalasteward/core/vcs/package.scala
@@ -73,50 +73,88 @@ package object vcs {
     possibleFilenames(baseNames)
   }
 
-  def possibleCompareUrls(repoUrl: Uri, update: Update): List[VersionDiff] = {
+  private[this] def extractRepoVCSType(
+      vcsType: SupportedVCS,
+      vcsUri: Uri,
+      repoUrl: Uri
+  ): Option[SupportedVCS] = {
     val host = repoUrl.host.map(_.value)
+    if (vcsUri.host.map(_.value).contains(host.getOrElse("")))
+      Option(vcsType)
+    else
+      host
+        .collect {
+          case "github.com" => GitHub
+          case "gitlab.com" => Gitlab
+        }
+        .orElse {
+          if (host.contains_("bitbucket.org"))
+            Some(Bitbucket)
+          else None
+        }
+  }
+
+  def possibleCompareUrls(
+      vcsType: SupportedVCS,
+      vcsUri: Uri,
+      repoUrl: Uri,
+      update: Update
+  ): List[VersionDiff] = {
     val from = update.currentVersion
     val to = update.nextVersion
 
-    if (host.exists(Set("github.com", "gitlab.com")))
-      possibleTags(from).zip(possibleTags(to)).map { case (from1, to1) =>
-        VersionDiff(repoUrl / "compare" / s"$from1...$to1")
-      }
-    else if (host.contains_("bitbucket.org"))
-      possibleTags(from).zip(possibleTags(to)).map { case (from1, to1) =>
-        VersionDiff((repoUrl / "compare" / s"$to1..$from1").withFragment("diff"))
+    extractRepoVCSType(vcsType, vcsUri, repoUrl)
+      .map {
+        case GitHub | Gitlab =>
+          possibleTags(from).zip(possibleTags(to)).map { case (from1, to1) =>
+            VersionDiff(repoUrl / "compare" / s"$from1...$to1")
+          }
+        case Bitbucket | BitbucketServer =>
+          possibleTags(from).zip(possibleTags(to)).map { case (from1, to1) =>
+            VersionDiff((repoUrl / "compare" / s"$to1..$from1").withFragment("diff"))
+          }
       }
-    else
-      List.empty
+      .getOrElse(List.empty)
   }
 
-  def possibleReleaseRelatedUrls(repoUrl: Uri, update: Update): List[ReleaseRelatedUrl] = {
-    val host = repoUrl.host.map(_.value)
-    val github =
-      if (host.contains_("github.com"))
+  def possibleReleaseRelatedUrls(
+      vcsType: SupportedVCS,
+      vcsUri: Uri,
+      repoUrl: Uri,
+      update: Update
+  ): List[ReleaseRelatedUrl] = {
+    val repoVCSType = extractRepoVCSType(vcsType, vcsUri, repoUrl)
+
+    val github = repoVCSType
+      .collect { case GitHub =>
         possibleTags(update.nextVersion).map(tag =>
           ReleaseRelatedUrl.GitHubReleaseNotes(repoUrl / "releases" / "tag" / tag)
         )
-      else
-        List.empty
+      }
+      .getOrElse(List.empty)
+
     def files(fileNames: List[String]): List[Uri] = {
-      val maybeSegments =
-        if (host.exists(Set("github.com", "gitlab.com")))
-          Some(List("blob", "master"))
-        else if (host.contains_("bitbucket.org"))
-          Some(List("master"))
-        else
-          None
+      val maybeSegments = repoVCSType.map {
+        case SupportedVCS.GitHub | SupportedVCS.Gitlab             => List("blob", "master")
+        case SupportedVCS.Bitbucket | SupportedVCS.BitbucketServer => List("master")
+      }
+
       maybeSegments.toList.flatMap { segments =>
         val base = segments.foldLeft(repoUrl)(_ / _)
         fileNames.map(name => base / name)
       }
     }
+
     val customChangelog = files(possibleChangelogFilenames).map(ReleaseRelatedUrl.CustomChangelog)
     val customReleaseNotes =
       files(possibleReleaseNotesFilenames).map(ReleaseRelatedUrl.CustomReleaseNotes)
 
-    github ++ customReleaseNotes ++ customChangelog ++ possibleCompareUrls(repoUrl, update)
+    github ++ customReleaseNotes ++ customChangelog ++ possibleCompareUrls(
+      vcsType,
+      vcsUri,
+      repoUrl,
+      update
+    )
   }
 
   private def possibleFilenames(baseNames: List[String]): List[String] = {


Test patch:
diff --git a/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSExtraAlgTest.scala b/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSExtraAlgTest.scala
index c6dbc68267..6112f4ae08 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSExtraAlgTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSExtraAlgTest.scala
@@ -7,8 +7,9 @@ import org.http4s.dsl.io._
 import org.http4s.implicits._
 import org.scalasteward.core.TestInstances.ioLogger
 import org.scalasteward.core.TestSyntax._
+import org.scalasteward.core.application.{Config, SupportedVCS}
 import org.scalasteward.core.data.{ReleaseRelatedUrl, Update}
-import org.scalasteward.core.mock.MockContext.config
+import org.scalasteward.core.mock.MockContext
 import org.scalasteward.core.util.{HttpExistenceClient, Nel}
 import org.scalatest.funsuite.AnyFunSuite
 import org.scalatest.matchers.should.Matchers
@@ -21,26 +22,52 @@ class VCSExtraAlgTest extends AnyFunSuite with Matchers {
       case _                                                            => NotFound()
     }
 
+  implicit val cfg = MockContext.config
   implicit val client = Client.fromHttpApp[IO](routes.orNotFound)
   implicit val httpExistenceClient =
     HttpExistenceClient.create[IO].allocated.map(_._1).unsafeRunSync()
 
-  val vcsExtraAlg = VCSExtraAlg.create[IO]
   val updateFoo = Update.Single("com.example" % "foo" % "0.1.0", Nel.of("0.2.0"))
   val updateBar = Update.Single("com.example" % "bar" % "0.1.0", Nel.of("0.2.0"))
   val updateBuz = Update.Single("com.example" % "buz" % "0.1.0", Nel.of("0.2.0"))
 
-  test("getBranchCompareUrl") {
+  test("getBranchCompareUrl: std vsc") {
+    val vcsExtraAlg = VCSExtraAlg.create[IO]
+
     vcsExtraAlg
       .getReleaseRelatedUrls(uri"https://github.com/foo/foo", updateFoo)
       .unsafeRunSync() shouldBe List.empty
+
     vcsExtraAlg
       .getReleaseRelatedUrls(uri"https://github.com/foo/bar", updateBar)
       .unsafeRunSync() shouldBe List(
       ReleaseRelatedUrl.VersionDiff(uri"https://github.com/foo/bar/compare/v0.1.0...v0.2.0")
     )
+
     vcsExtraAlg
       .getReleaseRelatedUrls(uri"https://github.com/foo/buz", updateBuz)
       .unsafeRunSync() shouldBe List.empty
   }
+
+  test("getBranchCompareUrl: github on prem") {
+    implicit val cfg: Config = MockContext.config.copy(
+      vcsType = SupportedVCS.GitHub,
+      vcsApiHost = uri"https://github.on-prem.com/"
+    )
+    val githubOnPremVcsExtraAlg = VCSExtraAlg.create[IO]
+
+    githubOnPremVcsExtraAlg
+      .getReleaseRelatedUrls(uri"https://github.on-prem.com/foo/foo", updateFoo)
+      .unsafeRunSync() shouldBe List.empty
+
+    githubOnPremVcsExtraAlg
+      .getReleaseRelatedUrls(uri"https://github.on-prem.com/foo/bar", updateBar)
+      .unsafeRunSync() shouldBe List(
+      ReleaseRelatedUrl.VersionDiff(uri"https://github.on-prem.com/foo/bar/compare/v0.1.0...v0.2.0")
+    )
+
+    githubOnPremVcsExtraAlg
+      .getReleaseRelatedUrls(uri"https://github.on-prem.com/foo/buz", updateFoo)
+      .unsafeRunSync() shouldBe List.empty
+  }
 }
diff --git a/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSPackageTest.scala b/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSPackageTest.scala
index f12a23bf6a..a40c0031d0 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSPackageTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/vcs/VCSPackageTest.scala
@@ -2,6 +2,7 @@ package org.scalasteward.core.vcs
 
 import org.http4s.syntax.literals._
 import org.scalasteward.core.TestSyntax._
+import org.scalasteward.core.application.SupportedVCS
 import org.scalasteward.core.application.SupportedVCS.{GitHub, Gitlab}
 import org.scalasteward.core.data.Update
 import org.scalasteward.core.util.Nel
@@ -25,38 +26,63 @@ class VCSPackageTest extends AnyFunSuite with Matchers {
   }
 
   test("possibleCompareUrls") {
-    possibleCompareUrls(uri"https://github.com/foo/bar", update)
+    val onPremVCS = "https://github.onprem.io/"
+    val onPremVCSUri = uri"https://github.onprem.io/"
+
+    possibleCompareUrls(SupportedVCS.GitHub, onPremVCSUri, uri"https://github.com/foo/bar", update)
       .map(_.url.renderString) shouldBe List(
       "https://github.com/foo/bar/compare/v1.2.0...v1.2.3",
       "https://github.com/foo/bar/compare/1.2.0...1.2.3",
       "https://github.com/foo/bar/compare/release-1.2.0...release-1.2.3"
     )
     // should canonicalize (drop last slash)
-    possibleCompareUrls(uri"https://github.com/foo/bar/", update)
+    possibleCompareUrls(SupportedVCS.GitHub, onPremVCSUri, uri"https://github.com/foo/bar/", update)
       .map(_.url.renderString) shouldBe List(
       "https://github.com/foo/bar/compare/v1.2.0...v1.2.3",
       "https://github.com/foo/bar/compare/1.2.0...1.2.3",
       "https://github.com/foo/bar/compare/release-1.2.0...release-1.2.3"
     )
 
-    possibleCompareUrls(uri"https://gitlab.com/foo/bar", update)
+    possibleCompareUrls(SupportedVCS.GitHub, onPremVCSUri, uri"https://gitlab.com/foo/bar", update)
       .map(_.url.renderString) shouldBe List(
       "https://gitlab.com/foo/bar/compare/v1.2.0...v1.2.3",
       "https://gitlab.com/foo/bar/compare/1.2.0...1.2.3",
       "https://gitlab.com/foo/bar/compare/release-1.2.0...release-1.2.3"
     )
-    possibleCompareUrls(uri"https://bitbucket.org/foo/bar", update)
+    possibleCompareUrls(
+      SupportedVCS.GitHub,
+      onPremVCSUri,
+      uri"https://bitbucket.org/foo/bar",
+      update
+    )
       .map(_.url.renderString) shouldBe List(
       "https://bitbucket.org/foo/bar/compare/v1.2.3..v1.2.0#diff",
       "https://bitbucket.org/foo/bar/compare/1.2.3..1.2.0#diff",
       "https://bitbucket.org/foo/bar/compare/release-1.2.3..release-1.2.0#diff"
     )
 
-    possibleCompareUrls(uri"https://scalacenter.github.io/scalafix/", update) shouldBe List()
+    possibleCompareUrls(
+      SupportedVCS.GitHub,
+      onPremVCSUri,
+      uri"https://scalacenter.github.io/scalafix/",
+      update
+    ) shouldBe List.empty
+
+    possibleCompareUrls(SupportedVCS.GitHub, onPremVCSUri, onPremVCSUri.addPath("/foo/bar"), update)
+      .map(_.url.renderString) shouldBe List(
+      s"${onPremVCS}foo/bar/compare/v1.2.0...v1.2.3",
+      s"${onPremVCS}foo/bar/compare/1.2.0...1.2.3",
+      s"${onPremVCS}foo/bar/compare/release-1.2.0...release-1.2.3"
+    )
   }
 
   test("possibleChangelogUrls: github.com") {
-    possibleReleaseRelatedUrls(uri"https://github.com/foo/bar", update)
+    possibleReleaseRelatedUrls(
+      SupportedVCS.GitHub,
+      uri"https://github.com",
+      uri"https://github.com/foo/bar",
+      update
+    )
       .map(_.url.renderString) shouldBe List(
       "https://github.com/foo/bar/releases/tag/v1.2.3",
       "https://github.com/foo/bar/releases/tag/1.2.3",
@@ -92,7 +118,12 @@ class VCSPackageTest extends AnyFunSuite with Matchers {
   }
 
   test("possibleChangelogUrls: gitlab.com") {
-    possibleReleaseRelatedUrls(uri"https://gitlab.com/foo/bar", update)
+    possibleReleaseRelatedUrls(
+      SupportedVCS.GitHub,
+      uri"https://github.com",
+      uri"https://gitlab.com/foo/bar",
+      update
+    )
       .map(_.url.renderString) shouldBe
       possibleReleaseNotesFilenames.map(name => s"https://gitlab.com/foo/bar/blob/master/$name") ++
       possibleChangelogFilenames.map(name => s"https://gitlab.com/foo/bar/blob/master/$name") ++
@@ -103,8 +134,34 @@ class VCSPackageTest extends AnyFunSuite with Matchers {
       )
   }
 
+  test("possibleChangelogUrls: on-prem gitlab") {
+    possibleReleaseRelatedUrls(
+      SupportedVCS.Gitlab,
+      uri"https://gitlab.on-prem.net",
+      uri"https://gitlab.on-prem.net/foo/bar",
+      update
+    )
+      .map(_.url.renderString) shouldBe
+      possibleReleaseNotesFilenames.map(name =>
+        s"https://gitlab.on-prem.net/foo/bar/blob/master/$name"
+      ) ++
+      possibleChangelogFilenames.map(name =>
+        s"https://gitlab.on-prem.net/foo/bar/blob/master/$name"
+      ) ++
+      List(
+        "https://gitlab.on-prem.net/foo/bar/compare/v1.2.0...v1.2.3",
+        "https://gitlab.on-prem.net/foo/bar/compare/1.2.0...1.2.3",
+        "https://gitlab.on-prem.net/foo/bar/compare/release-1.2.0...release-1.2.3"
+      )
+  }
+
   test("possibleChangelogUrls: bitbucket.org") {
-    possibleReleaseRelatedUrls(uri"https://bitbucket.org/foo/bar", update)
+    possibleReleaseRelatedUrls(
+      SupportedVCS.GitHub,
+      uri"https://github.com",
+      uri"https://bitbucket.org/foo/bar",
+      update
+    )
       .map(_.url.renderString) shouldBe
       possibleReleaseNotesFilenames.map(name => s"https://bitbucket.org/foo/bar/master/$name") ++
       possibleChangelogFilenames.map(name => s"https://bitbucket.org/foo/bar/master/$name") ++
@@ -116,7 +173,12 @@ class VCSPackageTest extends AnyFunSuite with Matchers {
   }
 
   test("possibleChangelogUrls: homepage") {
-    possibleReleaseRelatedUrls(uri"https://scalacenter.github.io/scalafix/", update)
-      .map(_.url.renderString) shouldBe List()
+    possibleReleaseRelatedUrls(
+      SupportedVCS.GitHub,
+      uri"https://github.com",
+      uri"https://scalacenter.github.io/scalafix/",
+      update
+    )
+      .map(_.url.renderString) shouldBe List.empty
   }
 }