diff --git a/build.sbt b/build.sbt index 9e647ff5..d14e4dd6 100644 --- a/build.sbt +++ b/build.sbt @@ -56,6 +56,13 @@ ThisBuild / missinglinkExcludedDependencies += moduleFilter( name = "slf4j-api" ) +ThisBuild / libraryDependencySchemes ++= Seq( + "io.circe" %% "circe-core" % "early-semver", + "io.circe" %% "circe-generic-extras" % "early-semver", + "io.circe" %% "circe-literal" % "early-semver", + "io.circe" %% "circe-parser" % "early-semver" +) + def crossPlugin(x: sbt.librarymanagement.ModuleID) = compilerPlugin(x.cross(CrossVersion.full)) @@ -71,16 +78,16 @@ val commonSettings = List( scalacOptions += "-Ymacro-annotations", libraryDependencies ++= List( "org.typelevel" %% "cats-core" % "2.6.1", - "org.typelevel" %% "cats-effect" % "2.5.1", + "org.typelevel" %% "cats-effect" % "3.1.1", "org.typelevel" %% "cats-tagless-macros" % "0.14.0", - "co.fs2" %% "fs2-core" % "2.5.6", - "com.github.valskalla" %% "odin-core" % "0.11.0", - "io.circe" %% "circe-core" % "0.13.0", + "co.fs2" %% "fs2-core" % "3.0.4", + "io.github.irevive" %% "odin-core" % "0.12.0-M3", + "io.circe" %% "circe-core" % "0.14.1", "com.github.julien-truffaut" %% "monocle-macro" % "2.1.0", - "com.disneystreaming" %% "weaver-framework" % "0.5.1" % Test, - "com.disneystreaming" %% "weaver-scalacheck" % "0.5.1" % Test + "com.disneystreaming" %% "weaver-cats" % "0.7.3" % Test, + "com.disneystreaming" %% "weaver-scalacheck" % "0.7.3" % Test ) ++ compilerPlugins, - testFrameworks += new TestFramework("weaver.framework.TestFramework"), + testFrameworks += new TestFramework("weaver.framework.CatsEffect"), publish / skip := true ) @@ -88,14 +95,14 @@ lazy val gitlab = project .settings( commonSettings, libraryDependencies ++= List( - "is.cir" %% "ciris" % "1.2.1", - "com.kubukoz" %% "caliban-gitlab" % "0.0.14", - "io.circe" %% "circe-generic-extras" % "0.13.0", - "io.circe" %% "circe-parser" % "0.13.0" % Test, - "io.circe" %% "circe-literal" % "0.13.0" % Test, - "com.softwaremill.sttp.tapir" %% "tapir-core" % "0.17.19", - "com.softwaremill.sttp.tapir" %% "tapir-json-circe" % "0.17.19", - "com.softwaremill.sttp.tapir" %% "tapir-sttp-client" % "0.17.19" + "is.cir" %% "ciris" % "2.0.1", + "com.kubukoz" %% "caliban-gitlab" % "0.1.0", + "io.circe" %% "circe-generic-extras" % "0.14.1", + "io.circe" %% "circe-parser" % "0.14.1" % Test, + "io.circe" %% "circe-literal" % "0.14.1" % Test, + "com.softwaremill.sttp.tapir" %% "tapir-core" % "0.18.0-M15", + "com.softwaremill.sttp.tapir" %% "tapir-json-circe" % "0.18.0-M15", + "com.softwaremill.sttp.tapir" %% "tapir-sttp-client" % "0.18.0-M15" ) ) .dependsOn(core) @@ -181,19 +188,19 @@ lazy val pitgull = buildInfoPackage := "io.pg", buildInfoKeys := List(version, scalaVersion), libraryDependencies ++= List( - "com.softwaremill.sttp.client3" %% "http4s-ce2-backend" % "3.3.6", - "org.http4s" %% "http4s-dsl" % "0.21.24", - "org.http4s" %% "http4s-circe" % "0.21.24", - "org.http4s" %% "http4s-blaze-server" % "0.21.24", - "org.http4s" %% "http4s-blaze-client" % "0.21.24", - "is.cir" %% "ciris" % "1.2.1", - "io.circe" %% "circe-generic-extras" % "0.13.0", + "com.softwaremill.sttp.client3" %% "http4s-backend" % "3.3.6", + "org.http4s" %% "http4s-dsl" % "0.23.0-RC1", + "org.http4s" %% "http4s-circe" % "0.23.0-RC1", + "org.http4s" %% "http4s-blaze-server" % "0.23.0-RC1", + "org.http4s" %% "http4s-blaze-client" % "0.23.0-RC1", + "is.cir" %% "ciris" % "2.0.1", + "io.circe" %% "circe-generic-extras" % "0.14.0", "io.estatico" %% "newtype" % "0.4.4", "io.scalaland" %% "chimney" % "0.6.1", "io.chrisdavenport" %% "cats-time" % "0.3.4", - "com.github.valskalla" %% "odin-core" % "0.11.0", - "com.github.valskalla" %% "odin-slf4j" % "0.11.0", - "io.github.vigoo" %% "prox-fs2" % "0.7.1" + "io.github.irevive" %% "odin-core" % "0.12.0-M3", + "io.github.irevive" %% "odin-slf4j" % "0.12.0-M3", + "io.github.vigoo" %% "prox-fs2-3" % "0.7.1" ) ) .dependsOn(core, gitlab) diff --git a/core/src/main/scala/io/pg/Prelude.scala b/core/src/main/scala/io/pg/Prelude.scala index e9109f5a..439a31e4 100644 --- a/core/src/main/scala/io/pg/Prelude.scala +++ b/core/src/main/scala/io/pg/Prelude.scala @@ -1,22 +1,6 @@ package io.pg -import cats.effect.Resource -import cats.syntax.functor._ -import cats.Applicative -import cats.MonadError - object Prelude { - type MonadThrow[F[_]] = MonadError[F, Throwable] - - implicit class EffectToResourceLiftSyntax[F[_], A](private val fa: F[A]) extends AnyVal { - - def resource(implicit F: Applicative[F]): Resource[F, A] = - Resource.eval(fa) - - def resource_(implicit F: Applicative[F]): Resource[F, Unit] = - fa.void.resource - - } implicit class AnythingAnything[A](private val a: A) extends AnyVal { def ??? : Nothing = ??? diff --git a/core/src/main/scala/io/pg/background/background.scala b/core/src/main/scala/io/pg/background/background.scala index 8e569e61..d47125b0 100644 --- a/core/src/main/scala/io/pg/background/background.scala +++ b/core/src/main/scala/io/pg/background/background.scala @@ -15,13 +15,13 @@ object BackgroundProcess { final case class DrainStream[F[_], G[_]]( stream: fs2.Stream[F, Nothing], - C: fs2.Stream.Compiler[F, G] + C: fs2.Compiler[F, G] ) extends BackgroundProcess[G] def fromStream[F[_], G[_]]( stream: fs2.Stream[F, _] )( - implicit C: fs2.Stream.Compiler[F, G] + implicit C: fs2.Compiler[F, G] ): BackgroundProcess[G] = new DrainStream(stream.drain, C) @@ -30,7 +30,7 @@ object BackgroundProcess { )( processor: Processor[F, A] )( - implicit C: fs2.Stream.Compiler[F, F] + implicit C: fs2.Compiler[F, F] ): BackgroundProcess[F] = fromStream(channel.consume.through(processor.process)) diff --git a/core/src/main/scala/io/pg/messaging/messaging.scala b/core/src/main/scala/io/pg/messaging/messaging.scala index c15be1d0..5588d18e 100644 --- a/core/src/main/scala/io/pg/messaging/messaging.scala +++ b/core/src/main/scala/io/pg/messaging/messaging.scala @@ -1,11 +1,12 @@ package io.pg.messaging -import fs2.concurrent.Queue +import cats.effect.std.Queue import scala.reflect.ClassTag import cats.tagless.autoInvariant import cats.syntax.all._ import cats.ApplicativeError import io.odin.Logger +import cats.Functor trait Publisher[F[_], -A] { def publish(a: A): F[Unit] @@ -41,10 +42,10 @@ trait Channel[F[_], A] extends Publisher[F, A] { self => object Channel { - def fromQueue[F[_], A](q: Queue[F, A]): Channel[F, A] = + def fromQueue[F[_]: Functor, A](q: Queue[F, A]): Channel[F, A] = new Channel[F, A] { - def publish(a: A): F[Unit] = q.enqueue1(a) - val consume: fs2.Stream[F, A] = q.dequeue + def publish(a: A): F[Unit] = q.offer(a) + val consume: fs2.Stream[F, A] = fs2.Stream.fromQueueUnterminated(q) } implicit class ChannelOpticsSyntax[F[_], A](val ch: Channel[F, A]) extends AnyVal { diff --git a/gitlab/src/main/scala/io/pg/gitlab/Gitlab.scala b/gitlab/src/main/scala/io/pg/gitlab/Gitlab.scala index fa47e913..abc5bfad 100644 --- a/gitlab/src/main/scala/io/pg/gitlab/Gitlab.scala +++ b/gitlab/src/main/scala/io/pg/gitlab/Gitlab.scala @@ -21,7 +21,7 @@ import io.pg.gitlab.graphql.PipelineStatusEnum import io.pg.gitlab.graphql.Project import io.pg.gitlab.graphql.ProjectConnection import io.pg.gitlab.graphql.Query -import io.pg.gitlab.graphql.User +import io.pg.gitlab.graphql.UserCore import sttp.client3.Request import sttp.client3.SttpBackend import sttp.model.Uri @@ -80,7 +80,7 @@ object Gitlab { accessToken: Secret[String] )( implicit backend: SttpBackend[F, Any], - SC: fs2.Stream.Compiler[F, F] + SC: fs2.Compiler[F, F] ): Gitlab[F] = { def runRequest[O](request: Request[O, Any]): F[O] = @@ -139,7 +139,7 @@ object Gitlab { MergeRequest.iid.mapEither(_.toLongOption.toRight(DecodingError("MR IID wasn't a Long"))) ~ MergeRequest.headPipeline(Pipeline.status.map(convertPipelineStatus)) ~ MergeRequest - .author(User.username) + .author(UserCore.username) .mapEither(_.toRight(DecodingError("MR has no author"))) ~ MergeRequest.description ~ MergeRequest.shouldBeRebased ~ diff --git a/src/main/java/org/slf4j/impl/StaticLoggerBinder.java b/src/main/java/org/slf4j/impl/StaticLoggerBinder.java index 23dfd3e4..af701a45 100644 --- a/src/main/java/org/slf4j/impl/StaticLoggerBinder.java +++ b/src/main/java/org/slf4j/impl/StaticLoggerBinder.java @@ -8,3 +8,4 @@ public static StaticLoggerBinder getSingleton() { return _instance; } } + diff --git a/src/main/scala/io/pg/Application.scala b/src/main/scala/io/pg/Application.scala index 82448784..40948d41 100644 --- a/src/main/scala/io/pg/Application.scala +++ b/src/main/scala/io/pg/Application.scala @@ -1,12 +1,11 @@ package io.pg import cats.data.NonEmptyList -import cats.effect.Blocker -import cats.effect.ConcurrentEffect -import cats.effect.ContextShift import cats.effect.Resource +import cats.effect.kernel.Async +import cats.effect.std.Queue +import cats.effect.implicits._ import cats.syntax.all._ -import fs2.concurrent.Queue import io.odin.Logger import io.pg.background.BackgroundProcess import io.pg.config.ProjectConfigReader @@ -15,7 +14,7 @@ import io.pg.gitlab.webhook.WebhookEvent import io.pg.messaging._ import io.pg.webhook._ import org.http4s.HttpApp -import org.http4s.client.blaze.BlazeClientBuilder +import org.http4s.blaze.client.BlazeClientBuilder import org.http4s.implicits._ import sttp.capabilities.fs2.Fs2Streams import sttp.client3.SttpBackend @@ -23,8 +22,6 @@ import sttp.client3.http4s.Http4sBackend import scala.concurrent.ExecutionContext -import Prelude._ - sealed trait Event extends Product with Serializable object Event { @@ -38,56 +35,54 @@ final class Application[F[_]]( object Application { - def resource[F[_]: ConcurrentEffect: ContextShift: Logger]( + def resource[F[_]: Logger: Async]( config: AppConfig ): Resource[F, Application[F]] = { implicit val projectConfigReader = ProjectConfigReader.test[F] - Blocker[F].flatMap { blocker => - Queue - .bounded[F, Event](config.queues.maxSize) - .map(Channel.fromQueue) - .resource - .flatMap { eventChannel => - implicit val webhookChannel: Channel[F, WebhookEvent] = - eventChannel.only[Event.Webhook].imap(_.value)(Event.Webhook) - - BlazeClientBuilder[F](ExecutionContext.global) - .resource - .map( - org - .http4s - .client - .middleware - .Logger(logHeaders = true, logBody = false, redactHeadersWhen = config.middleware.sensitiveHeaders.contains) + Queue + .bounded[F, Event](config.queues.maxSize) + .map(Channel.fromQueue(_)) + .toResource + .flatMap { eventChannel => + implicit val webhookChannel: Channel[F, WebhookEvent] = + eventChannel.only[Event.Webhook].imap(_.value)(Event.Webhook) + + BlazeClientBuilder[F](ExecutionContext.global) + .resource + .map( + org + .http4s + .client + .middleware + .Logger(logHeaders = true, logBody = false, redactHeadersWhen = config.middleware.sensitiveHeaders.contains) + ) + .map { client => + implicit val backend: SttpBackend[F, Fs2Streams[F]] = + Http4sBackend.usingClient[F](client) + + implicit val gitlab: Gitlab[F] = + Gitlab.sttpInstance[F](config.git.apiUrl, config.git.apiToken) + + implicit val projectActions: ProjectActions[F] = + ProjectActions.instance[F] + + implicit val stateResolver: StateResolver[F] = + StateResolver.instance[F] + + implicit val mergeRequests: MergeRequests[F] = + MergeRequests.instance[F] + + val webhookProcess = BackgroundProcess.fromProcessor( + webhookChannel + )(Processor.simple(WebhookProcessor.instance[F])) + + new Application[F]( + routes = WebhookRouter.routes[F].orNotFound, + background = NonEmptyList.one(webhookProcess) ) - .map { client => - implicit val backend: SttpBackend[F, Fs2Streams[F]] = - Http4sBackend.usingClient[F](client, blocker) - - implicit val gitlab: Gitlab[F] = - Gitlab.sttpInstance[F](config.git.apiUrl, config.git.apiToken) - - implicit val projectActions: ProjectActions[F] = - ProjectActions.instance[F] - - implicit val stateResolver: StateResolver[F] = - StateResolver.instance[F] - - implicit val mergeRequests: MergeRequests[F] = - MergeRequests.instance[F] - - val webhookProcess = BackgroundProcess.fromProcessor( - webhookChannel - )(Processor.simple(WebhookProcessor.instance[F])) - - new Application[F]( - routes = WebhookRouter.routes[F].orNotFound, - background = NonEmptyList.one(webhookProcess) - ) - } - } - } + } + } } } diff --git a/src/main/scala/io/pg/Main.scala b/src/main/scala/io/pg/Main.scala index 476eacb4..a77fa397 100644 --- a/src/main/scala/io/pg/Main.scala +++ b/src/main/scala/io/pg/Main.scala @@ -1,32 +1,30 @@ package io.pg -import scala.concurrent.ExecutionContext -import scala.concurrent.duration._ - -import cats.Parallel -import cats.effect.ConcurrentEffect -import cats.effect.ContextShift -import cats.effect.Effect import cats.effect.ExitCode import cats.effect.IO import cats.effect.IOApp import cats.effect.Resource import cats.effect.Sync -import cats.effect.Timer import cats.effect.implicits._ +import cats.effect.kernel.Async +import cats.effect.std.Dispatcher import cats.syntax.all._ +import cats.~> import io.chrisdavenport.cats.time.instances.all._ import io.odin.Level import io.odin.Logger import io.odin.formatter.Formatter -import io.pg.Prelude._ import org.http4s.HttpApp -import org.http4s.server.blaze.BlazeServerBuilder +import org.http4s.blaze.server.BlazeServerBuilder import org.http4s.server.middleware +import scala.concurrent.ExecutionContext +import scala.concurrent.duration._ +import cats.arrow.FunctionK + object Main extends IOApp { - def mkLogger[F[_]: ConcurrentEffect: Timer: ContextShift]: Resource[F, Logger[F]] = { + def mkLogger[F[_]: Async](fToIO: F ~> IO): Resource[F, Logger[F]] = { val console = io.odin.consoleLogger[F](formatter = Formatter.colorful).withMinimalLevel(Level.Info).pure[Resource[F, *]] @@ -44,10 +42,18 @@ object Main extends IOApp { console |+| file } .evalTap { logger => - Sync[F].delay(OdinInterop.globalLogger.set(logger.mapK(Effect.toIOK).some)) + Sync[F].delay( + OdinInterop + .globalLogger + .set( + logger + .mapK(fToIO) + .some + ) + ) } - def mkServer[F[_]: Logger: ConcurrentEffect: Timer]( + def mkServer[F[_]: Logger: Async]( config: AppConfig, routes: HttpApp[F] ) = { @@ -72,21 +78,21 @@ object Main extends IOApp { def logStarted[F[_]: Logger](meta: MetaConfig) = Logger[F].info("Started application", Map("version" -> meta.version, "scalaVersion" -> meta.scalaVersion)) - def serve[F[_]: ConcurrentEffect: ContextShift: Timer: Parallel](config: AppConfig) = + def serve[F[_]: Async](fToIO: F ~> IO)(config: AppConfig) = for { - implicit0(logger: Logger[F]) <- mkLogger[F] - _ <- logStarting(config.meta).resource_ + implicit0(logger: Logger[F]) <- mkLogger[F](fToIO) + _ <- logStarting(config.meta).toResource resources <- Application.resource[F](config) _ <- mkServer[F](config, resources.routes) _ <- resources.background.parTraverse_(_.run).background - _ <- logStarted(config.meta).resource_ + _ <- logStarted(config.meta).toResource } yield () def run(args: List[String]): IO[ExitCode] = AppConfig .appConfig .resource[IO] - .flatMap(serve[IO]) - .use(_ => IO.never) + .flatMap(serve[IO](FunctionK.id)) + .useForever } diff --git a/src/main/scala/io/pg/MergeRequests.scala b/src/main/scala/io/pg/MergeRequests.scala index f2ddffb4..58d3250e 100644 --- a/src/main/scala/io/pg/MergeRequests.scala +++ b/src/main/scala/io/pg/MergeRequests.scala @@ -25,7 +25,7 @@ object MergeRequests { import scala.util.chaining._ def instance[F[_]: ProjectConfigReader: StateResolver: Monad: Logger]( - implicit SC: fs2.Stream.Compiler[F, F] + implicit SC: fs2.Compiler[F, F] ): MergeRequests[F] = project => for { config <- ProjectConfigReader[F].readConfig(project) @@ -39,7 +39,7 @@ object MergeRequests { )( states: List[A] )( - implicit SC: fs2.Stream.Compiler[F, F] + implicit SC: fs2.Compiler[F, F] ): F[List[B]] = { def tapLeftAndDrop[L, R](log: L => F[Unit]): Pipe[F, Either[L, R], R] = _.evalTap(_.leftTraverse(log)).map(_.toOption).unNone diff --git a/src/main/scala/io/pg/OdinInterop.scala b/src/main/scala/io/pg/OdinInterop.scala index 6824c3fc..c3d22e6c 100644 --- a/src/main/scala/io/pg/OdinInterop.scala +++ b/src/main/scala/io/pg/OdinInterop.scala @@ -1,16 +1,18 @@ package io.pg -import java.util.concurrent.atomic.AtomicReference - -import cats.effect.Clock -import cats.effect.Effect import cats.effect.IO +import cats.effect.kernel.Sync +import cats.effect.std.Dispatcher +import cats.effect.unsafe.implicits._ import io.odin.Logger import io.odin.slf4j.OdinLoggerBinder +import java.util.concurrent.atomic.AtomicReference + class OdinInterop extends OdinLoggerBinder[IO] { - implicit val F: Effect[IO] = IO.ioEffect - implicit val clock: Clock[IO] = Clock.create[IO] + implicit val F: Sync[IO] = IO.asyncForIO + + implicit val dispatcher: Dispatcher[IO] = Dispatcher[IO].allocated.unsafeRunSync()._1 val loggers: PartialFunction[String, Logger[IO]] = { val theLogger: String => Option[Logger[IO]] = _ => OdinInterop.globalLogger.get() @@ -21,5 +23,5 @@ class OdinInterop extends OdinLoggerBinder[IO] { } object OdinInterop { - val globalLogger = new AtomicReference[Option[Logger[IO]]](None) + val globalLogger: AtomicReference[Option[Logger[IO]]] = new AtomicReference[Option[Logger[IO]]](None) } diff --git a/src/main/scala/io/pg/actions.scala b/src/main/scala/io/pg/actions.scala index 3819bbc6..afd44f7e 100644 --- a/src/main/scala/io/pg/actions.scala +++ b/src/main/scala/io/pg/actions.scala @@ -8,7 +8,6 @@ import io.pg.config.Matcher import io.pg.config.ProjectConfig import io.pg.gitlab.Gitlab import io.odin.Logger -import io.pg.Prelude.MonadThrow import io.pg.gitlab.Gitlab.MergeRequestInfo import io.pg.config.TextMatcher import cats.MonoidK @@ -20,6 +19,7 @@ import io.pg.MergeRequestState.Mergeability.HasConflicts import cats.Applicative import cats.data.NonEmptyList import scala.util.matching.Regex +import cats.MonadThrow trait ProjectActions[F[_]] { type Action diff --git a/src/main/scala/io/pg/appconfig.scala b/src/main/scala/io/pg/appconfig.scala index 11d834ed..b866bfca 100644 --- a/src/main/scala/io/pg/appconfig.scala +++ b/src/main/scala/io/pg/appconfig.scala @@ -3,9 +3,8 @@ package io.pg import cats.syntax.all._ import ciris.Secret import org.http4s.Headers -import org.http4s.util.CaseInsensitiveString -import org.http4s.syntax.all._ import sttp.model.Uri +import org.typelevel.ci.CIString final case class AppConfig( http: HttpConfig, @@ -31,10 +30,10 @@ object AppConfig { import ciris._ - val httpConfig: ConfigValue[HttpConfig] = + val httpConfig: ConfigValue[ciris.Effect, HttpConfig] = env("HTTP_PORT").as[Int].default(8080).map(HttpConfig(_)) - val metaConfig: ConfigValue[MetaConfig] = + val metaConfig: ConfigValue[ciris.Effect, MetaConfig] = ( default(bannerString), default(BuildInfo.version), @@ -48,19 +47,19 @@ object AppConfig { .leftMap(e => ConfigError(s"Invalid URI ($value at $key), error: $e")) } - val gitConfig: ConfigValue[Git] = + val gitConfig: ConfigValue[ciris.Effect, Git] = ( default(Git.Host.Gitlab), env("GIT_API_URL").as[Uri], env("GIT_API_TOKEN").secret ).mapN(Git.apply) - private val queuesConfig: ConfigValue[Queues] = default(100).map(Queues) + private val queuesConfig: ConfigValue[ciris.Effect, Queues] = default(100).map(Queues) - private val middlewareConfig: ConfigValue[MiddlewareConfig] = - default(Headers.SensitiveHeaders + "Private-Token".ci).map(MiddlewareConfig) + private val middlewareConfig: ConfigValue[ciris.Effect, MiddlewareConfig] = + default(Headers.SensitiveHeaders + CIString("Private-Token")).map(MiddlewareConfig) - val appConfig: ConfigValue[AppConfig] = + val appConfig: ConfigValue[ciris.Effect, AppConfig] = (httpConfig, metaConfig, gitConfig, queuesConfig, middlewareConfig).parMapN(apply) } @@ -86,4 +85,4 @@ object Git { final case class Queues(maxSize: Int) -final case class MiddlewareConfig(sensitiveHeaders: Set[CaseInsensitiveString]) +final case class MiddlewareConfig(sensitiveHeaders: Set[CIString]) diff --git a/src/main/scala/io/pg/config/ProjectConfig.scala b/src/main/scala/io/pg/config/ProjectConfig.scala index 5e7a8c37..9cf54429 100644 --- a/src/main/scala/io/pg/config/ProjectConfig.scala +++ b/src/main/scala/io/pg/config/ProjectConfig.scala @@ -56,7 +56,7 @@ object ProjectConfigReader { def dhallJsonStringConfig[F[_]: ProxFS2: MonadThrow]: F[ProjectConfigReader[F]] = { val prox: ProxFS2[F] = implicitly - import prox.{contextShift => _, blocker => _, concurrent => _, _} + import prox._ val dhallCommand = "dhall-to-json" //todo: not reading a local file diff --git a/src/main/scala/io/pg/resolver.scala b/src/main/scala/io/pg/resolver.scala index 5c42abdf..023de848 100644 --- a/src/main/scala/io/pg/resolver.scala +++ b/src/main/scala/io/pg/resolver.scala @@ -20,7 +20,7 @@ trait StateResolver[F[_]] { object StateResolver { def instance[F[_]: Gitlab: Logger: MonadError[*[_], Throwable]]( - implicit SC: fs2.Stream.Compiler[F, F] + implicit SC: fs2.Compiler[F, F] ): StateResolver[F] = new StateResolver[F] { diff --git a/src/main/scala/io/pg/webhook/webhook.scala b/src/main/scala/io/pg/webhook/webhook.scala index f4366d28..5b8d613c 100644 --- a/src/main/scala/io/pg/webhook/webhook.scala +++ b/src/main/scala/io/pg/webhook/webhook.scala @@ -1,6 +1,5 @@ package io.pg.webhook -import cats.Defer import cats.Monad import cats.MonadError import cats.implicits._ @@ -19,7 +18,7 @@ import org.http4s.dsl.Http4sDsl object WebhookRouter { - def routes[F[_]: MergeRequests: JsonDecoder: Defer: Monad]( + def routes[F[_]: MergeRequests: JsonDecoder: Monad]( implicit eventPublisher: Publisher[F, WebhookEvent] ): HttpRoutes[F] = { val dsl = new Http4sDsl[F] {} diff --git a/src/test/scala/io/pg/MainTest.scala b/src/test/scala/io/pg/MainTest.scala index 55618f58..357951b2 100644 --- a/src/test/scala/io/pg/MainTest.scala +++ b/src/test/scala/io/pg/MainTest.scala @@ -1,6 +1,6 @@ package io.pg -import cats.effect.IO +import cats.arrow.FunctionK import ciris.Secret import sttp.model.Uri._ import weaver.SimpleIOSuite @@ -15,6 +15,6 @@ object MainTest extends SimpleIOSuite { middleware = MiddlewareConfig(Set()) ) - Main.serve(testConfig).use(IO.pure).as(success) + Main.serve(FunctionK.id)(testConfig).use_.as(success) } } diff --git a/src/test/scala/io/pg/WebhookProcessorTest.scala b/src/test/scala/io/pg/WebhookProcessorTest.scala index 1922726a..caabab7e 100644 --- a/src/test/scala/io/pg/WebhookProcessorTest.scala +++ b/src/test/scala/io/pg/WebhookProcessorTest.scala @@ -2,7 +2,7 @@ package io.pg import cats.effect.IO import cats.implicits._ -import io.pg.Prelude._ +import cats.effect.implicits._ import io.pg.config.ProjectConfig import io.pg.config.ProjectConfigReader import io.pg.fakes.ProjectActionsStateFake @@ -48,7 +48,7 @@ object WebhookProcessorTest extends SimpleIOSuite { ) } } - .resource + .toResource def testWithResources(name: String)(use: Resources[IO] => IO[Expectations]) = test(name)(mkResources.use(use)) diff --git a/src/test/scala/io/pg/fakes/FakeUtils.scala b/src/test/scala/io/pg/fakes/FakeUtils.scala index 4d91ca1b..dfa2b852 100644 --- a/src/test/scala/io/pg/fakes/FakeUtils.scala +++ b/src/test/scala/io/pg/fakes/FakeUtils.scala @@ -2,7 +2,7 @@ package io.pg.fakes import cats.Monad import cats.mtl.Stateful -import cats.effect.concurrent.Ref +import cats.effect.Ref object FakeUtils { diff --git a/src/test/scala/io/pg/fakes/ProjectActionsStateFake.scala b/src/test/scala/io/pg/fakes/ProjectActionsStateFake.scala index 53e0905e..7fc2a0fa 100644 --- a/src/test/scala/io/pg/fakes/ProjectActionsStateFake.scala +++ b/src/test/scala/io/pg/fakes/ProjectActionsStateFake.scala @@ -1,23 +1,22 @@ package io.pg.fakes +import cats.Monad +import cats.data.Chain +import cats.effect.Ref +import cats.implicits._ import cats.mtl.Stateful -import monocle.macros.Lenses +import io.odin.Logger +import io.pg.MergeRequestState +import io.pg.MergeRequestState.Mergeability +import io.pg.ProjectAction +import io.pg.ProjectAction.Merge +import io.pg.ProjectAction.Rebase import io.pg.ProjectActions import io.pg.StateResolver -import io.pg.ProjectAction -import io.pg.MergeRequestState +import io.pg.gitlab.Gitlab.MergeRequestInfo import io.pg.gitlab.webhook.Project -import io.pg.ProjectAction.Merge import io.scalaland.chimney.dsl._ -import cats.implicits._ -import cats.effect.Sync -import cats.effect.concurrent.Ref -import io.pg.gitlab.Gitlab.MergeRequestInfo -import io.pg.MergeRequestState.Mergeability -import io.pg.ProjectAction.Rebase -import cats.data.Chain -import cats.Monad -import io.odin.Logger +import monocle.macros.Lenses object ProjectActionsStateFake { sealed case class MergeRequestDescription(projectId: Long, mergeRequestIid: Long) @@ -82,7 +81,7 @@ object ProjectActionsStateFake { type Data[F[_]] = Stateful[F, State] def Data[F[_]: Data]: Data[F] = implicitly[Data[F]] - def refInstance[F[_]: Sync: Logger]: F[ProjectActions[F] with StateResolver[F] with State.Modifiers[F]] = + def refInstance[F[_]: Ref.Make: Logger: Monad]: F[ProjectActions[F] with StateResolver[F] with State.Modifiers[F]] = Ref[F].of(State.initial).map(FakeUtils.statefulRef(_)).map(implicit F => instance[F]) /** This instance has both the capabilities of ProjectActions and StateResolver, diff --git a/src/test/scala/io/pg/fakes/ProjectConfigReaderFake.scala b/src/test/scala/io/pg/fakes/ProjectConfigReaderFake.scala index 328bd96d..4597dd3b 100644 --- a/src/test/scala/io/pg/fakes/ProjectConfigReaderFake.scala +++ b/src/test/scala/io/pg/fakes/ProjectConfigReaderFake.scala @@ -1,14 +1,13 @@ package io.pg.fakes -import cats.MonadError +import cats.MonadThrow +import cats.effect.Ref import cats.implicits._ import cats.mtl.Stateful import io.pg.config.ProjectConfig import io.pg.config.ProjectConfigReader import io.pg.gitlab.webhook.Project import monocle.macros.Lenses -import cats.effect.Sync -import cats.effect.concurrent.Ref trait FakeState @@ -33,10 +32,10 @@ object ProjectConfigReaderFake { type Data[F[_]] = Stateful[F, State] def Data[F[_]: Data]: Data[F] = implicitly[Data[F]] - def refInstance[F[_]: Sync]: F[ProjectConfigReader[F] with State.Modifiers[F]] = + def refInstance[F[_]: Ref.Make: MonadThrow]: F[ProjectConfigReader[F] with State.Modifiers[F]] = Ref[F].of(State(Map.empty)).map(FakeUtils.statefulRef(_)).map(implicit F => instance[F]) - def instance[F[_]: Data: MonadError[*[_], Throwable]]: ProjectConfigReader[F] with State.Modifiers[F] = + def instance[F[_]: Data: MonadThrow]: ProjectConfigReader[F] with State.Modifiers[F] = new ProjectConfigReader[F] with State.Modifiers[F] { def readConfig(project: Project): F[ProjectConfig] =