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

Update deps, add Scala 3 support, drop Scala 2.12 #134

Merged
merged 1 commit into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,21 @@ jobs:
strategy:
matrix:
scala:
- 2.13.8
- 2.12.17
- 2.13.14
- 3.3.3

steps:
- uses: actions/checkout@v3

- uses: coursier/cache-action@v6

- name: scala
uses: olafurpg/setup-scala@v13
uses: olafurpg/setup-scala@v14
with:
java-version: 17

- name: build ${{ matrix.scala }}
run: sbt ++${{ matrix.scala }} clean coverage test
run: sbt ++${{ matrix.scala }} clean check coverage test

- name: test coverage
if: success()
Expand Down
52 changes: 47 additions & 5 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Dependencies._
import Dependencies.*

name := "conhub"

Expand All @@ -14,13 +14,22 @@ organizationHomepage := Some(url("https://evolution.com"))

scalaVersion := crossScalaVersions.value.head

crossScalaVersions := Seq("2.13.8", "2.12.17")
crossScalaVersions := Seq("2.13.14", "3.3.3")

Compile / scalacOptions ++= {
if (scalaBinaryVersion.value == "2.13") {
Seq(
"-Xsource:3"
)
} else Seq.empty
}

Test / fork := true

publishTo := Some(Resolver.evolutionReleases)

libraryDependencies ++= Seq(
`scodec-bits`,
Akka.actor,
Akka.remote,
Akka.cluster,
Expand All @@ -38,6 +47,18 @@ libraryDependencies ++= Seq(
`scala-tools` % Test,
scalatest % Test)

libraryDependencies ++= {
if (scalaBinaryVersion.value == "2.13") {
Seq(
`scodec-core1`,
)
} else {
Seq(
`scodec-core2`,
)
}
}

licenses := Seq(("MIT", url("https://opensource.org/licenses/MIT")))

releaseCrossBuild := true
Expand All @@ -46,6 +67,27 @@ Compile / doc / scalacOptions ++= Seq("-groups", "-implicits", "-no-link-warning

versionScheme := Some("semver-spec")

//addCommandAlias("check", "all versionPolicyCheck Compile/doc")
addCommandAlias("check", "show version")
addCommandAlias("build", "+all compile test")
addCommandAlias("check", "+all versionPolicyCheck Compile/doc")
addCommandAlias("build", "+all test package")

// Your next release will be binary compatible with the previous one,
// but it may not be source compatible (ie, it will be a minor release).
ThisBuild / versionPolicyIntention := Compatibility.BinaryCompatible

/*
versionPolicyReportDependencyIssues ignored dependencies when compared to conhub 1.2.1.
All of those should not affect the library users, binary compatibility should be preserved.

Remember to clear up after 1.3.0 release!
*/
ThisBuild / versionPolicyIgnored ++= Seq(
/*
Examples:

//com.chuusai:shapeless_2.13: missing dependency
"com.chuusai" %% "shapeless",
//org.scala-lang.modules:scala-java8-compat_2.13:
// incompatible version change from 0.9.0 to 1.0.0 (compatibility: early semantic versioning)
"org.scala-lang.modules" %% "scala-java8-compat",
*/
)
30 changes: 14 additions & 16 deletions project/Dependencies.scala
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
import sbt._
import sbt.*

object Dependencies {

val `config-tools` = "com.evolutiongaming" %% "config-tools" % "1.0.4"
val `future-helper` = "com.evolutiongaming" %% "future-helper" % "1.0.6"
val sequentially = "com.evolutiongaming" %% "sequentially" % "1.1.4"
val `akka-serialization` = "com.evolutiongaming" %% "akka-serialization" % "1.0.4"
val nel = "com.evolutiongaming" %% "nel" % "1.3.4"
val `safe-actor` = "com.evolutiongaming" %% "safe-actor" % "3.0.0"
val `scala-tools` = "com.evolutiongaming" %% "scala-tools" % "3.0.5"
val scalatest = "org.scalatest" %% "scalatest" % "3.2.14"
val `config-tools` = "com.evolutiongaming" %% "config-tools" % "1.0.5"
val `future-helper` = "com.evolutiongaming" %% "future-helper" % "1.0.7"
val sequentially = "com.evolutiongaming" %% "sequentially" % "1.2.0"
val `akka-serialization` = "com.evolutiongaming" %% "akka-serialization" % "1.1.0"
edubrovski marked this conversation as resolved.
Show resolved Hide resolved
val nel = "com.evolutiongaming" %% "nel" % "1.3.5"
edubrovski marked this conversation as resolved.
Show resolved Hide resolved
val `safe-actor` = "com.evolutiongaming" %% "safe-actor" % "3.1.0"
val `scala-tools` = "com.evolutiongaming" %% "scala-tools" % "3.0.6"
val scalatest = "org.scalatest" %% "scalatest" % "3.2.19"
val `scala-logging` = "com.typesafe.scala-logging" %% "scala-logging" % "3.9.5"
val `scodec-bits` = "org.scodec" %% "scodec-bits" % "1.2.1"
val `scodec-core1` = "org.scodec" %% "scodec-core" % "1.11.10"
edubrovski marked this conversation as resolved.
Show resolved Hide resolved
val `scodec-core2` = "org.scodec" %% "scodec-core" % "2.3.1"

object Akka {
private val version = "2.6.19"
private val version = "2.6.21"
val actor = "com.typesafe.akka" %% "akka-actor" % version
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if we should bump Akka because it's patch versions are incompatible, so we can potentially get this error in downstream dependencies if they depend on Akka 2.6.19

java.lang.IllegalStateException: You are using version 2.6.21 of Akka, but it appears you (perhaps indirectly) also depend on older versions of related artifacts

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe everyone should be on 2.6.21 already, it doesn't seem to be a problem.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and most of our OSS base akka support libraries are on 2.6.21 for months already

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we use .20 via overrides. The fact that our libraries are on .21 is a problem and not a reason for others to bump it too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am afraid that it will sound arrogant, but prohibiting upgrades for all other projects because your one cannot or doesn't want to update is not a solution we can accept.

You are free to put overrides in your project or to not update some library at your own risk.

Please review changes in akka (https://github.com/akka/akka/releases/tag/v2.6.21) - they are very small and, most probably, will not have negative affect on your project.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I stand with @mr-git here - Akka 2.6.21 is more than 1 year old now. If there is an internal reason for us to use older versions internally, there is no reason to have an outdated version in the opensource. Updating Akka 19 and 20 to 21 is trivial and by just trying to hold it in transitive dependencies is a loosing game. There are already dependencies which will bring 2.6.21 transitively (like safe-akka). If you want safeguards, they should be on the library client side - dependency overrides and such.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vilunov, am I right that we (including you) are using Akka 2.6.21 now? Shall we unblock the PR?

val remote = "com.typesafe.akka" %% "akka-remote" % version
val cluster = "com.typesafe.akka" %% "akka-cluster" % version
Expand All @@ -23,12 +26,7 @@ object Dependencies {
}

object AkkaTools {
private val version = "3.0.12"
private val version = "3.0.13"
val test = "com.evolutiongaming" %% "akka-tools-test" % version
}

object Scodec {
val core = "org.scodec" %% "scodec-core" % "1.11.3"
val bits = "org.scodec" %% "scodec-bits" % "1.1.9"
}
}
2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version=1.7.2
sbt.version=1.10.1
10 changes: 6 additions & 4 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.6")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.2.0")

addSbtPlugin("org.scoverage" % "sbt-coveralls" % "1.3.2")
addSbtPlugin("org.scoverage" % "sbt-coveralls" % "1.3.13")

addSbtPlugin("com.github.sbt" % "sbt-release" % "1.1.0")
addSbtPlugin("com.github.sbt" % "sbt-release" % "1.4.0")

addSbtPlugin("com.evolution" % "sbt-scalac-opts-plugin" % "0.0.9")

addSbtPlugin("com.evolution" % "sbt-artifactory-plugin" % "0.0.2")
addSbtPlugin("com.evolution" % "sbt-artifactory-plugin" % "0.0.2")

addSbtPlugin("ch.epfl.scala" % "sbt-version-policy" % "3.2.1")
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import akka.actor.ActorSystem

import scala.concurrent.ExecutionContext

final case class NamedDispatcher(name: String, implicit val ec: ExecutionContext)
@deprecated(message = "roll out your own NamedDispatcher, this one will be removed", since = "1.3.0")
final case class NamedDispatcher(name: String, ec: ExecutionContext)

@deprecated(message = "roll out your own NamedDispatcher, this one will be removed", since = "1.3.0")
object NamedDispatcher {

def apply(actorSystem: ActorSystem): NamedDispatcher = {
Expand Down
5 changes: 3 additions & 2 deletions src/main/scala/com/evolutiongaming/conhub/ConHub.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ object ConHub {
def !(msg: M): SR

/**
* @param msg messages will be delivered to all matched connections whether it is Local or Remote connection
* @param msgs messages will be delivered to all matched connections whether it is Local or Remote connection
* @return list of local connections that matched the message
*/
def !(msgs: Nel[M]): SR
Expand All @@ -44,7 +44,8 @@ object ConHub {

def cons: Iterable[C] = conStates.values.values

def consLocal: Iterable[C.Local] = cons.collect { case x: C.Local => x }
//@unchecked needed to work around a Scala 3.3.3 compiler quirk with pattern matching
def consLocal: Iterable[C.Local] = cons.collect { case x: C.Local@unchecked => x }

def consRemote: Iterable[C.Remote] = cons.collect { case x: C.Remote => x }
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/com/evolutiongaming/conhub/ConHubImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import java.util.concurrent.atomic.AtomicBoolean

import com.evolutiongaming.concurrent.sequentially.Sequentially
import com.evolutiongaming.nel.Nel
import com.evolutiongaming.concurrent.FutureHelper._
import com.evolutiongaming.concurrent.FutureHelper.*
import com.typesafe.scalalogging.LazyLogging

import scala.concurrent.duration.FiniteDuration
Expand Down Expand Up @@ -43,7 +43,7 @@ object ConHubImpl extends LazyLogging {
executor: ExecutionContext
): ConHub[Id, A, M, L] = {

implicit val executor1 = executor
implicit val executor1: ExecutionContext = executor

new ConHub[Id, A, M, L] {

Expand Down
15 changes: 10 additions & 5 deletions src/main/scala/com/evolutiongaming/conhub/ConHubSerializer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ package com.evolutiongaming.conhub
import java.io.NotSerializableException

import akka.serialization.SerializerWithStringManifest
import com.evolutiongaming.conhub.{RemoteEvent => R}
import com.evolutiongaming.conhub.RemoteEvent as R
import com.evolutiongaming.nel.Nel
import scodec.bits.{BitVector, ByteVector}
import scodec.{Attempt, Codec, DecodeResult, codecs}

import scala.concurrent.duration._
import scala.annotation.nowarn
import scala.concurrent.duration.*

class ConHubSerializer extends SerializerWithStringManifest {
import ConHubSerializer._
import ConHubSerializer.*

private val EventManifest = "A"
private val MsgsManifest = "C"
Expand Down Expand Up @@ -43,6 +44,10 @@ class ConHubSerializer extends SerializerWithStringManifest {
}
}

//suppresses comp warning for 2.13 with -Xsource:3
@nowarn(
"msg=Implicit method .+ was found in a package prefix of the required type, which is not part of the implicit scope in Scala 3"
)
object ConHubSerializer {

val codecBytes: Codec[ByteVector] = codecs.variableSizeBytes(codecs.int32, codecs.bytes)
Expand All @@ -68,9 +73,9 @@ object ConHubSerializer {

private val codecSync = codecsNel(codecValue).as[RemoteEvent.Event.Sync]

private def notSerializable(msg: String) = throw new NotSerializableException(msg)
private def notSerializable(msg: String): Nothing = throw new NotSerializableException(msg)

private def illegalArgument(msg: String) = throw new IllegalArgumentException(msg)
private def illegalArgument(msg: String): Nothing = throw new IllegalArgumentException(msg)


private def eventFromBinary(bits: BitVector) = {
Expand Down
13 changes: 8 additions & 5 deletions src/main/scala/com/evolutiongaming/conhub/ConStates.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import java.time.Instant

import akka.actor.{Address, Scheduler}
import com.evolutiongaming.concurrent.sequentially.{MapDirective, SequentialMap}
import com.evolutiongaming.conhub.SequentialMapHelper._
import com.evolutiongaming.conhub.SequentialMapHelper.*
import com.typesafe.scalalogging.LazyLogging
import scodec.bits.ByteVector

Expand Down Expand Up @@ -70,7 +70,7 @@ object ConStates {

private val send: SendEvent[Id, A] = connect(this)

def values = states.values
def values: collection.Map[Id, C] = states.values

def update(id: Id, con: C.Local): Result = {
updatePf(id, Some(con.version), "update") { case before =>
Expand Down Expand Up @@ -111,7 +111,8 @@ object ConStates {
}

(ctx, c) match {
case (Ctx.Local, _: C.Local) => disconnect(local = true)
//@unchecked needed to work around a Scala 3.3.3 compiler quirk with pattern matching
case (Ctx.Local, _: C.Local@unchecked) => disconnect(local = true)
case (ctx: Ctx.Remote, c: C.Remote) if c.address == ctx.address => disconnect(local = false)
case _ => R.Ignore
}
Expand All @@ -130,7 +131,8 @@ object ConStates {
def remove(local: Boolean) = this.remove(id, version, local)

(ctx, c) match {
case (Ctx.Local, _: C.Local) => remove(local = true)
//@unchecked needed to work around a Scala 3.3.3 compiler quirk with pattern matching
case (Ctx.Local, _: C.Local@unchecked) => remove(local = true)
case (ctx: Ctx.Remote, c: C.Remote) if c.address == ctx.address => remove(local = false)
case (_, _: C.Disconnected) => remove(local = ctx == Ctx.Local)
case _ => R.Ignore
Expand All @@ -139,7 +141,8 @@ object ConStates {
}

def sync(id: Id) = {
updatePf(id, None, "sync") { case Some(c: C.Local) =>
//@unchecked needed to work around a Scala 3.3.3 compiler quirk with pattern matching
updatePf(id, None, "sync") { case Some(c: C.Local@unchecked) =>
send.sync(id, c.value, c.version)
R.Ignore
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.evolutiongaming.conhub

import akka.actor.{Actor, ActorRefFactory, Props}
import akka.cluster.Cluster
import akka.cluster.ClusterEvent._
import akka.cluster.ClusterEvent.*
import com.evolutiongaming.safeakka.actor.ActorLog

object MemberEventSubscribe {
Expand All @@ -16,8 +16,9 @@ object MemberEventSubscribe {
onEvent: MemberEvent => Unit): Unsubscribe = {

def actor() = new Actor {
lazy val log = ActorLog(context.system, MemberEventSubscribe.getClass)
def receive = {
private lazy val log = ActorLog(context.system, classOf[MemberEventSubscribe.type])

def receive: Receive = {
case x: CurrentClusterState => onState(x)
case x: MemberEvent => onEvent(x)
case x => log.warn(s"unexpected $x")
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/com/evolutiongaming/conhub/SendEvent.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.evolutiongaming.conhub

import akka.actor.{ActorRefFactory, ActorSystem, Address}
import com.evolutiongaming.conhub.transport.{ReceiveMsg, SendMsg}
import com.evolutiongaming.conhub.{RemoteEvent => R}
import com.evolutiongaming.conhub.RemoteEvent as R
import com.evolutiongaming.nel.Nel

import scala.concurrent.duration.FiniteDuration
Expand Down
10 changes: 6 additions & 4 deletions src/main/scala/com/evolutiongaming/conhub/SendMsgs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ object SendMsgs {

def apply(msg: M, con: C.Connected): Unit = {
con match {
case con: C.Local => con.send(MsgAndRemote(msg))
case con: C.Remote => remote(Nel(msg), List(con.address))
//@unchecked needed to work around a Scala 3.3.3 compiler quirk with pattern matching
case con: C.Local@unchecked => con.send(MsgAndRemote(msg))
case con: C.Remote => remote(Nel(msg), List(con.address))
}
}

Expand All @@ -33,8 +34,9 @@ object SendMsgs {
def local(msg: M, cons: Iterable[C], remote: Boolean): Unit = {
val msgAndRemote = MsgAndRemote(msg, remote)
for {con <- cons} con match {
case x: C.Local => x.send(msgAndRemote)
case _ =>
//@unchecked needed to work around a Scala 3.3.3 compiler quirk with pattern matching
case x: C.Local@unchecked => x.send(msgAndRemote)
case _ =>
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package com.evolutiongaming.conhub

import com.evolutiongaming.concurrent.CurrentThreadExecutionContext
import com.evolutiongaming.concurrent.sequentially.{MapDirective, SequentialMap}

import scala.concurrent.Future
import scala.concurrent.{ExecutionContext, Future}

object SequentialMapHelper {

Expand All @@ -25,7 +24,7 @@ object SequentialMapHelper {
value: V,
onUpdated: (K, Set[V], Set[V]) => Unit = (_, _, _) => ()): Future[Unit] = {

implicit val ec = CurrentThreadExecutionContext
implicit val ec: ExecutionContext = ExecutionContext.parasitic
edubrovski marked this conversation as resolved.
Show resolved Hide resolved

if (before != after) {
val futureBefore = before.fold(Future.unit) { key => updateSet(key)(_ - value, onUpdated(key, _, _)) }
Expand Down Expand Up @@ -59,6 +58,6 @@ object SequentialMapHelper {
implicit class FutureOps[A](val self: Future[A]) extends AnyVal {

// to execute f strictly in order of future origin
def mapNow[B](f: A => B): Future[B] = self.map(f)(CurrentThreadExecutionContext)
def mapNow[B](f: A => B): Future[B] = self.map(f)(ExecutionContext.parasitic)
}
}
Loading
Loading