Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

all: prepare for Scala3 #36

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
89fbc64
all: prepare for Scala3
ahjohannessen Apr 4, 2023
2f856a2
Activate Scala 3
mkurz Nov 21, 2023
7a576f5
Some imports needed by Scala 3
mkurz Nov 21, 2023
8f81fbf
Import needed by Scala 3
mkurz Nov 21, 2023
71c6813
WIP Comment some flags Scala 3 does not like
mkurz Nov 21, 2023
956dbb0
Using Scala 3 type projection with match types, WIP
ndeverge Nov 24, 2023
7f1e8d7
Temporary removal of Scala 2.13 to focus on Scala 3 migration.
ndeverge Nov 24, 2023
a899acd
Silence warnings
Nov 24, 2023
b25a388
Use izumi reflect as workaround scala reflect runtime
Nov 24, 2023
882b4bc
Start fixing some compile errors
Nov 24, 2023
0502c04
Fixes
Nov 27, 2023
46243f1
Fixes
Nov 27, 2023
826ff5b
Rollback removal of context
Nov 27, 2023
16e9d27
Fix some compilation errors
Nov 27, 2023
85f635d
Fixes
Nov 27, 2023
02ca153
Fix other specs2 errors
Nov 27, 2023
4a9c6ed
Fix overloading errors
Nov 28, 2023
950dc39
Fix imports
Nov 28, 2023
88780fd
Fix guice implicit conversions
Nov 28, 2023
f25f378
Add running wrapper for play specs with scala 3
Nov 28, 2023
4cab39b
Fix some providers tests
Nov 28, 2023
ddae063
Fix tests for scala 3
Nov 28, 2023
4ab8fc9
Fix tests JWTAuthenticatorSpecs
Nov 29, 2023
9fcb3e3
Enable cross compile
MathisGuillet1 Nov 29, 2023
76234e4
Fully working cross compiled version
MathisGuillet1 Nov 29, 2023
7fe2b61
Build cleanup
MathisGuillet1 Nov 29, 2023
a63b0bb
Disable Xlint-all flag
MathisGuillet1 Nov 29, 2023
b56e1d3
Switch default to scala 3
MathisGuillet1 Nov 29, 2023
df8b5f3
Switch back default to scala 2
MathisGuillet1 Nov 29, 2023
eed5074
Remove (unused) helpers that rely on Around
mkurz Dec 8, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,12 @@ dist
/.target
/.cache
*.DS_Store
.bsp/

# Metals
.metals/*
.bloop/*
.vscode/*
**/.bloop/*
**/metals.sbt

.bsp/*
59 changes: 29 additions & 30 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import sbt.CrossVersion

lazy val repo: String = "https://s01.oss.sonatype.org"
lazy val scala213: String = "2.13.12"
lazy val scala3: String = "3.3.1" // Ready for cross build, currently not yet supported by play.
lazy val supportedScalaVersions: Seq[String] = Seq(scala213 /*, scala3*/)
lazy val scala3: String = "3.3.1"
lazy val supportedScalaVersions: Seq[String] = Seq(scala213, scala3)

Global / evictionErrorLevel := Level.Info

ThisBuild / description := "Authentication library for Play Framework applications that supports several authentication methods, including OAuth1, OAuth2, OpenID, CAS, Credentials, Basic Authentication, Two Factor Authentication or custom authentication schemes"
ThisBuild / homepage := Some(url("https://silhouette.readme.io/"))
Expand All @@ -17,17 +19,21 @@ ThisBuild / organizationName := "honeycomb-cheesecake"
ThisBuild / scalaVersion := scala213
ThisBuild / versionScheme := Some("early-semver")
ThisBuild / scalacOptions ++= Seq(
"-unchecked",
"-deprecation",
"-feature",
"-encoding", "utf8",
"-Xfatal-warnings",
"-Xlint",
"-Xlint:adapted-args",
"-Xlint:inaccessible",
"-Xlint:infer-any",
"-Xlint:nullary-unit"
)
"-Xfatal-warnings"
) ++
(CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, _)) => Seq(
"-encoding", "utf8",
"-unchecked",
"-deprecation",
"-Xlint:adapted-args",
"-Xlint:inaccessible",
"-Xlint:infer-any",
"-Xlint:nullary-unit"
)
case _ => Seq()
})
ThisBuild / Test / scalacOptions ~= { options: Seq[String] =>
// Allow dead code in tests (to support using mockito).
options filterNot (_ == "-Ywarn-dead-code")
Expand Down Expand Up @@ -98,8 +104,6 @@ lazy val root = (project in file("."))
lazy val silhouette = (project in file("silhouette"))
.settings(
name := "play-silhouette",
dependencyUpdatesFilter -= moduleFilter(organization = "org.specs2", name = "specs2-matcher-extra"),
dependencyUpdatesFilter -= moduleFilter(organization = "org.specs2", name = "specs2-mock"),
libraryDependencies ++=
Library.updates ++ Seq(
Library.Play.cache,
Expand All @@ -109,27 +113,26 @@ lazy val silhouette = (project in file("silhouette"))
Library.apacheCommonLang,
Library.Play.specs2 % Test,
Library.Specs2.matcherExtra % Test,
Library.Specs2.mock % Test,
Library.mockito % Test,
Library.scalaGuice % Test,
Library.akkaTestkit % Test
),
resolvers ++= Dependencies.resolvers
)
.enablePlugins(PlayScala)
.disablePlugins(PlayAkkaHttpServer)

lazy val silhouetteCas = (project in file("silhouette-cas"))
.settings(
name := "play-silhouette-cas",
dependencyUpdatesFailBuild := false,
dependencyUpdatesFilter -= moduleFilter(organization = "org.specs2", name = "specs2-matcher-extra"),
dependencyUpdatesFilter -= moduleFilter(organization = "org.specs2", name = "specs2-mock"),
libraryDependencies ++=
Library.updates ++ Seq(
Library.casClient,
Library.casClientSupportSAML,
Library.Play.specs2 % Test,
Library.Specs2.matcherExtra % Test,
Library.Specs2.mock % Test,
Library.mockito % Test,
Library.scalaGuice % Test
)
)
Expand All @@ -139,7 +142,6 @@ lazy val silhouetteTotp = (project in file("silhouette-totp"))
.settings(
name := "play-silhouette-totp",
dependencyUpdatesFailBuild := false,
dependencyUpdatesFilter -= moduleFilter(organization = "org.specs2", name = "specs2-core"),
libraryDependencies ++=
Library.updates ++ Seq(
Library.googleAuth,
Expand All @@ -152,8 +154,6 @@ lazy val silhouetteCryptoJca = (project in file("silhouette-crypto-jca"))
.settings(
name := "play-silhouette-crypto-jca",
dependencyUpdatesFailBuild := false,
dependencyUpdatesFilter -= moduleFilter(organization = "org.specs2", name = "specs2-core"),
dependencyUpdatesFilter -= moduleFilter(organization = "org.specs2", name = "specs2-matcher-extra"),
libraryDependencies ++=
Library.updates ++ Seq(
Library.commonsCodec,
Expand All @@ -167,7 +167,6 @@ lazy val silhouetteArgon2 = (project in file("silhouette-password-argon2"))
.settings(
name := "play-silhouette-password-argon2",
dependencyUpdatesFailBuild := false,
dependencyUpdatesFilter -= moduleFilter(organization = "org.specs2", name = "specs2-core"),
libraryDependencies ++=
Library.updates ++ Seq(
Library.argon2,
Expand All @@ -180,7 +179,6 @@ lazy val silhouetteBcrypt = (project in file("silhouette-password-bcrypt"))
.settings(
name := "play-silhouette-password-bcrypt",
dependencyUpdatesFailBuild := false,
dependencyUpdatesFilter -= moduleFilter(organization = "org.specs2", name = "specs2-core"),
libraryDependencies ++=
Library.updates ++ Seq(
Library.jbcrypt,
Expand All @@ -193,14 +191,11 @@ lazy val silhouettePersistence = (project in file("silhouette-persistence"))
.settings(
name := "play-silhouette-persistence",
dependencyUpdatesFailBuild := false,
dependencyUpdatesFilter -= moduleFilter(organization = "org.specs2", name = "specs2-core"),
dependencyUpdatesFilter -= moduleFilter(organization = "org.specs2", name = "specs2-matcher-extra"),
dependencyUpdatesFilter -= moduleFilter(organization = "org.specs2", name = "specs2-mock"),
libraryDependencies ++=
Library.updates ++ Seq(
Library.Specs2.core % Test,
Library.Specs2.matcherExtra % Test,
Library.Specs2.mock % Test,
Library.mockito % Test,
Library.scalaGuice % Test
)
)
Expand All @@ -210,17 +205,21 @@ lazy val silhouetteTestkit = (project in file("silhouette-testkit"))
.settings(
name := "play-silhouette-testkit",
dependencyUpdatesFailBuild := false,
dependencyUpdatesFilter -= moduleFilter(organization = "org.specs2", name = "specs2-matcher-extra"),
dependencyUpdatesFilter -= moduleFilter(organization = "org.specs2", name = "specs2-mock"),
libraryDependencies ++=
Library.updates ++ Seq(
Library.Play.test,
Library.Play.specs2 % Test,
Library.Specs2.matcherExtra % Test,
Library.Specs2.mock % Test,
Library.mockito % Test,
Library.scalaGuice % Test,
Library.akkaTestkit % Test
)
++ {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((3, _)) => Seq(Library.izumiReflect)
case _ => Seq.empty
}
}
)
.enablePlugins(PlayScala)
.dependsOn(silhouette)
Expand Down
5 changes: 3 additions & 2 deletions project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@ object Dependencies {
}

object Specs2 {
private val version = "4.20.2" // Versions later than this will fail due to removed dependencies.
private val version = "4.20.2"
val core = "org.specs2" %% "specs2-core" % version
val matcherExtra = "org.specs2" %% "specs2-matcher-extra" % version
val mock = "org.specs2" %% "specs2-mock" % version
}

val argon2 = "de.mkammerer" % "argon2-jvm" % "2.11"
Expand All @@ -47,9 +46,11 @@ object Dependencies {
val jwt = "com.auth0" % "java-jwt" % "3.18.2"
val scalaGuice = "net.codingwell" %% "scala-guice" % "6.0.0"
val akkaTestkit = "com.typesafe.akka" %% "akka-testkit" % play.core.PlayVersion.akkaVersion
val mockito = "org.mockito" % "mockito-core" % "5.3.0"
val casClient = "org.jasig.cas.client" % "cas-client-core" % "3.6.4"
val casClientSupportSAML = "org.jasig.cas.client" % "cas-client-support-saml" % "3.6.4"
val apacheCommonLang = "org.apache.commons" % "commons-lang3" % "3.13.0"
val googleAuth = "com.warrenstrange" % "googleauth" % "1.5.0"
val izumiReflect = "dev.zio" %% "izumi-reflect" % "2.3.8" // Scala 3 replacement for scala 2 reflect universe
}
}
2 changes: 1 addition & 1 deletion project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ addSbtPlugin(dependency = "com.github.sbt" % "sbt-unidoc" % "0.5.0")
addSbtPlugin(dependency = "com.jsuereth" % "sbt-pgp" % "2.1.1")
addSbtPlugin(dependency = "com.timushev.sbt" % "sbt-updates" % "0.6.4")
addSbtPlugin(dependency = "com.typesafe.play" % "sbt-plugin" % "2.9.0")
addSbtPlugin(dependency = "net.vonbuchholtz" % "sbt-dependency-check" % "4.0.0")
addSbtPlugin(dependency = "net.vonbuchholtz" % "sbt-dependency-check" % "5.1.0")
addSbtPlugin(dependency = "org.scoverage" % "sbt-scoverage" % "2.0.9")
addSbtPlugin(dependency = "org.scoverage" % "sbt-coveralls" % "1.3.11")
addSbtPlugin(dependency = "org.xerial.sbt" % "sbt-sonatype" % "3.10.0")
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import io.github.honeycombcheesecake.play.silhouette.api.util.HTTPLayer
import io.github.honeycombcheesecake.play.silhouette.api.{ Logger, LoginInfo }

import org.jasig.cas.client.authentication.AttributePrincipal
import org.specs2.mock.Mockito
import org.mockito.Mockito._
import org.specs2.specification.Scope
import play.api.mvc.AnyContentAsEmpty
import play.api.test.FakeRequest
Expand All @@ -33,7 +33,7 @@ import scala.concurrent.duration._
/**
* Test case for the [[CasProvider]] class.
*/
class CasProviderSpec extends SocialProviderSpec[CasInfo] with Mockito with Logger {
class CasProviderSpec extends SocialProviderSpec[CasInfo] with Logger {

"The settings" should {
"fail with a ConfigurationException if casURL is invalid" in new Context {
Expand Down Expand Up @@ -95,9 +95,9 @@ class CasProviderSpec extends SocialProviderSpec[CasInfo] with Mockito with Logg

"The `retrieveProfile` method" should {
"return a valid profile if the CAS client validates the ticket" in new Context {
principal.getName returns userName
principal.getAttributes returns attr
client.validateServiceTicket(ticket) returns Future.successful(principal)
when(principal.getName).thenReturn(userName)
when(principal.getAttributes).thenReturn(attr)
when(client.validateServiceTicket(ticket)).thenReturn(Future.successful(principal))

implicit val req: FakeRequest[AnyContentAsEmpty.type] = FakeRequest(GET, "/?ticket=%s".format(ticket))

Expand Down Expand Up @@ -129,8 +129,8 @@ class CasProviderSpec extends SocialProviderSpec[CasInfo] with Mockito with Logg
redirectURL = "https://cas-redirect/")

lazy val httpLayer = {
val m = mock[HTTPLayer]
m.executionContext returns global
val m = mock(classOf[HTTPLayer])
when(m.executionContext).thenReturn(global)
m
}

Expand All @@ -144,7 +144,7 @@ class CasProviderSpec extends SocialProviderSpec[CasInfo] with Mockito with Logg

lazy val casAuthInfo = CasInfo(ticket)

lazy val principal = mock[AttributePrincipal].smart
lazy val principal = mock(classOf[AttributePrincipal], withSettings().defaultAnswer(RETURNS_SMART_NULLS))

lazy val name = "abc123"
lazy val email = "email"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package io.github.honeycombcheesecake.play.silhouette.persistence.daos
import io.github.honeycombcheesecake.play.silhouette.api.{ AuthInfo, LoginInfo }
import io.github.honeycombcheesecake.play.silhouette.test.WaitPatience
import org.specs2.concurrent.ExecutionEnv
import org.specs2.control.NoLanguageFeatures
import org.specs2.mutable.Specification
import org.specs2.specification.Scope

Expand All @@ -29,7 +28,7 @@ import scala.language.postfixOps
/**
* Test case for the [[InMemoryAuthInfoDAO]] trait.
*/
class InMemoryAuthInfoDAOSpec(implicit ev: ExecutionEnv) extends Specification with NoLanguageFeatures with WaitPatience {
class InMemoryAuthInfoDAOSpec(implicit ev: ExecutionEnv) extends Specification with WaitPatience {

"The `find` method" should {
"find an OAuth1 info for the given login info" in new Context {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,60 +19,60 @@ import io.github.honeycombcheesecake.play.silhouette.api.StorableAuthenticator
import io.github.honeycombcheesecake.play.silhouette.api.util.CacheLayer
import io.github.honeycombcheesecake.play.silhouette.test.WaitPatience
import org.specs2.concurrent.ExecutionEnv
import org.specs2.mock.Mockito
import org.specs2.mutable.Specification
import org.specs2.specification.Scope
import org.mockito.Mockito._

import scala.concurrent.Future
import scala.concurrent.duration.Duration

/**
* Test case for the [[CacheAuthenticatorRepository]] class.
*/
class CacheAuthenticatorRepositorySpec(implicit ev: ExecutionEnv) extends Specification with Mockito with WaitPatience {
class CacheAuthenticatorRepositorySpec(implicit ev: ExecutionEnv) extends Specification with WaitPatience {

"The `find` method" should {
"return value from cache" in new Context {
cacheLayer.find[StorableAuthenticator]("test-id") returns Future.successful(Some(authenticator))
when(cacheLayer.find[StorableAuthenticator]("test-id")).thenReturn(Future.successful(Some(authenticator)))

repository.find("test-id") must beSome(authenticator).awaitWithPatience
there was one(cacheLayer).find[StorableAuthenticator]("test-id")
verify(cacheLayer).find[StorableAuthenticator]("test-id")
}

"return None if value couldn't be found in cache" in new Context {
cacheLayer.find[StorableAuthenticator]("test-id") returns Future.successful(None)
when(cacheLayer.find[StorableAuthenticator]("test-id")).thenReturn(Future.successful(None))

repository.find("test-id") must beNone.awaitWithPatience
there was one(cacheLayer).find[StorableAuthenticator]("test-id")
verify(cacheLayer).find[StorableAuthenticator]("test-id")
}
}

"The `add` method" should {
"add value in cache" in new Context {
authenticator.id returns "test-id"
cacheLayer.save("test-id", authenticator, Duration.Inf) returns Future.successful(authenticator)
when(authenticator.id).thenReturn("test-id")
when(cacheLayer.save("test-id", authenticator, Duration.Inf)).thenReturn(Future.successful(authenticator))

repository.add(authenticator) must beEqualTo(authenticator).awaitWithPatience
there was one(cacheLayer).save("test-id", authenticator, Duration.Inf)
verify(cacheLayer).save("test-id", authenticator, Duration.Inf)
}
}

"The `update` method" should {
"update value in cache" in new Context {
authenticator.id returns "test-id"
cacheLayer.save("test-id", authenticator, Duration.Inf) returns Future.successful(authenticator)
when(authenticator.id).thenReturn("test-id")
when(cacheLayer.save("test-id", authenticator, Duration.Inf)).thenReturn(Future.successful(authenticator))

repository.update(authenticator) must beEqualTo(authenticator).awaitWithPatience
there was one(cacheLayer).save("test-id", authenticator, Duration.Inf)
verify(cacheLayer).save("test-id", authenticator, Duration.Inf)
}
}

"The `remove` method" should {
"remove value from cache" in new Context {
cacheLayer.remove("test-id") returns Future.successful(())
when(cacheLayer.remove("test-id")).thenReturn(Future.successful(()))

repository.remove("test-id") must beEqualTo(()).awaitWithPatience
there was one(cacheLayer).remove("test-id")
verify(cacheLayer).remove("test-id")
}
}

Expand All @@ -84,12 +84,12 @@ class CacheAuthenticatorRepositorySpec(implicit ev: ExecutionEnv) extends Specif
/**
* A storable authenticator.
*/
lazy val authenticator = mock[StorableAuthenticator]
lazy val authenticator = mock(classOf[StorableAuthenticator])

/**
* The cache layer implementation.
*/
lazy val cacheLayer = mock[CacheLayer]
lazy val cacheLayer = mock(classOf[CacheLayer])

/**
* The repository to test.
Expand Down
Loading