Skip to content

Commit

Permalink
Rework badges:
Browse files Browse the repository at this point in the history
- Use ProjectHeader instead of ArtifactSelection
- Only show latest version for Mill or sbt plugins
- Only show latest version for Java lib
  • Loading branch information
adpi2 committed Jan 13, 2025
1 parent d8dbc60 commit a94c4a5
Show file tree
Hide file tree
Showing 6 changed files with 25 additions and 91 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,6 @@ case class ArtifactSelection(
private def filterAll(artifact: Artifact.Reference): Boolean =
binaryVersion.forall(_ == artifact.binaryVersion) && artifactNames.forall(_ == artifact.name)

def defaultArtifact(artifacts: Seq[Artifact.Reference], project: Project): Option[Artifact.Reference] =
val filteredArtifacts = artifacts.view.filter(filterAll)

filteredArtifacts.maxByOption { artifact =>
(
// default artifact (ex: akka-actors is the default for akka/akka)
project.settings.defaultArtifact.contains(artifact.name),
// not deprecated
!project.settings.deprecatedArtifacts.contains(artifact.name),
// project repository (ex: shapeless)
project.repository.value == artifact.name.value,
// alphabetically
artifact.name,
// stable version first
project.settings.preferStableVersion && !artifact.version.isStable,
artifact.version,
artifact.binaryVersion
)
}(
Ordering.Tuple7(
Ordering[Boolean],
Ordering[Boolean],
Ordering[Boolean],
Ordering[Artifact.Name].reverse,
Ordering[Boolean].reverse,
Ordering[Version],
Ordering[BinaryVersion]
)
)
end defaultArtifact

def filterArtifacts(artifacts: Seq[Artifact.Reference], project: Project): Seq[Artifact.Reference] =
artifacts
.filter(filterAll)
Expand Down Expand Up @@ -70,6 +39,3 @@ case class ArtifactSelection(
.reverse
)
end ArtifactSelection

object ArtifactSelection:
def empty = new ArtifactSelection(None, None)
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ final case class ProjectHeader(
def allArtifactNames: Seq[Artifact.Name] = artifacts.map(_.name).distinct.sorted
def platforms(artifactName: Artifact.Name): Seq[Platform] =
artifacts.filter(_.name == artifactName).map(_.platform).distinct.sorted(Platform.ordering.reverse)
def artifacts(artifactName: Artifact.Name, platform: Platform): Seq[Artifact] =
artifacts.filter(a => a.name == artifactName && a.platform == platform)

def versionsUrl: String = artifactsUrl(getDefaultArtifact(None, None), withBinaryVersion = false)

Expand All @@ -43,16 +45,22 @@ final case class ProjectHeader(
val queryParams = if filters.nonEmpty then "?" + filters.mkString("&") else ""
s"/$ref/artifacts/${defaultArtifact.name}$queryParams"

def getDefaultArtifact0(binaryVersion: Option[BinaryVersion], artifactName: Option[Artifact.Name]): Artifact =
getDefaultArtifact(binaryVersion.map(_.language), binaryVersion.map(_.platform), artifactName)

def getDefaultArtifact(language: Option[Language], platform: Option[Platform]): Artifact =
getDefaultArtifact(language, platform, None)

/** getDefaultArtifact is split in two steps: first we get the default artifact name and then, the latest version. The
* reason is, we cannot use the latest version of all artifacts to get the default artifact if they don't share the
* same versioning. Instead we use the latest release date. But once we have the artifact with the latest release
* date, we really want to get the latest version of that artifact, which is not necessarily the latest one released
* because of back-publishing.
*/
def getDefaultArtifact(language: Option[Language], platform: Option[Platform]): Artifact =
val artifactName = getDefaultArtifactName(language, platform)
def getDefaultArtifact(language: Option[Language], platform: Option[Platform], artifactName: Option[Artifact.Name]): Artifact =
val defaultArtifactName = artifactName.getOrElse(getDefaultArtifactName(language, platform))
val filteredArtifacts = artifacts.filter { a =>
a.name == artifactName && language.forall(_ == a.language) && platform.forall(_ == a.platform)
a.name == defaultArtifactName && language.forall(_ == a.language) && platform.forall(_ == a.platform)
}
if preferStableVersion then filteredArtifacts.maxBy(a => (a.version.isStable, a.version))
else filteredArtifacts.maxBy(_.version)
Expand Down

This file was deleted.

2 changes: 1 addition & 1 deletion modules/server/src/main/scala/scaladex/server/Server.scala
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ object Server extends LazyLogging:
val publishApi = new PublishApi(githubAuth, publishProcess)
val apiEndpoints = new ApiEndpointsImpl(projectService, artifactService, searchEngine)
val oldSearchApi = new OldSearchApi(searchEngine, webDatabase)
val badges = new Badges(webDatabase)
val badges = new Badges(projectService)
val authentication = new AuthenticationApi(config.oAuth2.clientId, config.session, githubAuth, webDatabase)

val route: Route =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,7 @@ class OldSearchApi(searchEngine: SearchEngine, database: WebDatabase)(using Exec
binaryVersion: Option[BinaryVersion],
artifact: Option[String]
): Future[Option[OldSearchApi.ArtifactOptions]] =
val selection = new ArtifactSelection(
binaryVersion = binaryVersion,
artifactNames = artifact.map(Artifact.Name.apply)
)
val selection = new ArtifactSelection(binaryVersion = binaryVersion, artifactNames = artifact.map(Artifact.Name.apply))
for
projectOpt <- database.getProject(projectRef)
stableOnly = projectOpt.map(_.settings.preferStableVersion).getOrElse(false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import scala.concurrent.Await
import scala.concurrent.Future
import scala.concurrent.duration.Duration

import scaladex.core.model.Scala.*
import scaladex.core.model.*
import scaladex.core.test.Values.*
import scaladex.server.route.Badges.summaryOfLatestVersions
import scaladex.server.route.Badges.*

import org.apache.pekko.http.scaladsl.model.StatusCodes
import org.apache.pekko.http.scaladsl.model.Uri
Expand All @@ -18,14 +18,14 @@ import org.scalatest.matchers.should.Matchers

class BadgesTests extends ControllerBaseSuite with BeforeAndAfterAll:

val badgesRoute: Route = new Badges(database).route
val route: Route = new Badges(projectService).route

override protected def beforeAll(): Unit =
val f = Future.traverse(Cats.allArtifacts)(artifactService.insertArtifact(_, Seq.empty))
Await.result(f, Duration.Inf)

it("fallback to JVM artifacts") {
Get(s"/${Cats.reference}/cats-core/latest-by-scala-version.svg") ~> badgesRoute ~> check {
Get(s"/${Cats.reference}/cats-core/latest-by-scala-version.svg") ~> route ~> check {
status shouldEqual StatusCodes.TemporaryRedirect
val redirection = headers.collectFirst { case Location(uri) => uri }
redirection should contain(
Expand All @@ -35,7 +35,7 @@ class BadgesTests extends ControllerBaseSuite with BeforeAndAfterAll:
}

it("fallback to sjs1 when targetType is js") {
Get(s"/${Cats.reference}/cats-core/latest-by-scala-version.svg?targetType=js") ~> badgesRoute ~> check {
Get(s"/${Cats.reference}/cats-core/latest-by-scala-version.svg?targetType=js") ~> route ~> check {
status shouldEqual StatusCodes.TemporaryRedirect
val redirection = headers.collectFirst { case Location(uri) => uri }
redirection should contain(
Expand All @@ -45,7 +45,7 @@ class BadgesTests extends ControllerBaseSuite with BeforeAndAfterAll:
}

it("latest version for Scala.js 0.6") {
Get(s"/${Cats.reference}/cats-core/latest-by-scala-version.svg?platform=sjs0.6") ~> badgesRoute ~> check {
Get(s"/${Cats.reference}/cats-core/latest-by-scala-version.svg?platform=sjs0.6") ~> route ~> check {
status shouldEqual StatusCodes.TemporaryRedirect
val redirection = headers.collectFirst { case Location(uri) => uri }
redirection should contain(
Expand All @@ -55,7 +55,7 @@ class BadgesTests extends ControllerBaseSuite with BeforeAndAfterAll:
}

it("latest version for Scala native 0.4") {
Get(s"/${Cats.reference}/cats-core/latest-by-scala-version.svg?platform=native0.4") ~> badgesRoute ~> check {
Get(s"/${Cats.reference}/cats-core/latest-by-scala-version.svg?platform=native0.4") ~> route ~> check {
status shouldEqual StatusCodes.TemporaryRedirect
val redirection = headers.collectFirst { case Location(uri) => uri }
redirection should contain(
Expand All @@ -67,23 +67,16 @@ end BadgesTests

class BadgesUnitTests extends AnyFunSpec with Matchers:
it("should provide a concise summary of latest versions") {
summaryOfLatestVersions(
Map(
`2.11` -> Seq(`7.0.0`, `7.1.0`),
`2.12` -> Seq(`7.0.0`, `7.1.0`, `7.2.0`),
`2.13` -> Seq(`7.0.0`, `7.1.0`, `7.2.0`, `7.3.0`),
`3` -> Seq(`7.2.0`, `7.3.0`)
)
) shouldBe "7.3.0 (Scala 3.x, 2.13), 7.2.0 (Scala 2.12), 7.1.0 (Scala 2.11)"
val versions: Map[Language, Version] =
Map(Scala.`2.11` -> `7.1.0`, Scala.`2.12` -> `7.2.0`, Scala.`2.13` -> `7.3.0`, Scala.`3` -> `7.3.0`)
summaryByLanguageVersion(versions) shouldBe "7.3.0 (Scala 3.x, 2.13), 7.2.0 (Scala 2.12), 7.1.0 (Scala 2.11)"
}

it("should prefer stable to pre-releases if both are available") {
summaryOfLatestVersions(Map(`2.13` -> Seq(`7.0.0`, `7.1.0`, `7.2.0-PREVIEW.1`))) shouldBe "7.1.0 (Scala 2.13)"
summaryByLanguageVersion(Map(Scala.`2.13` -> `7.1.0`)) shouldBe "7.1.0 (Scala 2.13)"
}

it("should display latest pre-release if no full release is available") {
summaryOfLatestVersions(
Map(`2.13` -> Seq(`7.2.0-PREVIEW.1`, `7.2.0-PREVIEW.2`))
) shouldBe s"${`7.2.0-PREVIEW.2`} (Scala 2.13)"
summaryByLanguageVersion(Map(Scala.`2.13` -> `7.2.0-PREVIEW.2`)) shouldBe s"7.2.0-PREVIEW.2 (Scala 2.13)"
}
end BadgesUnitTests

0 comments on commit a94c4a5

Please sign in to comment.