Skip to content

Commit

Permalink
Merge pull request #431 from polyvariant/scala3
Browse files Browse the repository at this point in the history
  • Loading branch information
kubukoz committed May 21, 2022
2 parents 06c8a6f + 20fe87f commit c666413
Show file tree
Hide file tree
Showing 22 changed files with 311 additions and 191 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/ci.yml
Expand Up @@ -22,7 +22,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
scala: [2.13.6]
scala: [3.1.1]
java: [graalvm-ce-java11@20.1.0]
runs-on: ${{ matrix.os }}
steps:
Expand Down Expand Up @@ -78,7 +78,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
scala: [2.13.6]
scala: [3.1.1]
java: [graalvm-ce-java11@20.1.0]
runs-on: ${{ matrix.os }}
steps:
Expand All @@ -104,12 +104,12 @@ jobs:
~/Library/Caches/Coursier/v1
key: ${{ runner.os }}-sbt-cache-v2-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }}

- name: Download target directories (2.13.6)
- name: Download target directories (3.1.1)
uses: actions/download-artifact@v2
with:
name: target-${{ matrix.os }}-2.13.6-${{ matrix.java }}
name: target-${{ matrix.os }}-3.1.1-${{ matrix.java }}

- name: Inflate target directories (2.13.6)
- name: Inflate target directories (3.1.1)
run: |
tar xf targets.tar
rm targets.tar
Expand Down
2 changes: 1 addition & 1 deletion .scalafmt.conf
@@ -1,4 +1,4 @@
runner.dialect=scala213
runner.dialect=scala3

version = "3.5.3"
maxColumn = 140
Expand Down
34 changes: 14 additions & 20 deletions build.sbt
Expand Up @@ -2,6 +2,8 @@ import com.typesafe.sbt.packager.docker.Cmd

import com.typesafe.sbt.packager.docker.ExecCmd

Global / onChangedBuildSource := ReloadOnSourceChanges

inThisBuild(
List(
organization := "io.pg",
Expand All @@ -22,9 +24,9 @@ inThisBuild(

val GraalVM11 = "graalvm-ce-java11@20.1.0"

val Scala213 = "2.13.6"
ThisBuild / scalaVersion := Scala213
ThisBuild / crossScalaVersions := Seq(Scala213)
val Scala3 = "3.1.1"
ThisBuild / scalaVersion := Scala3
ThisBuild / crossScalaVersions := Seq(Scala3)
ThisBuild / githubWorkflowJavaVersions := Seq(GraalVM11)

ThisBuild / githubWorkflowPublishTargetBranches := Seq(
Expand Down Expand Up @@ -67,23 +69,18 @@ def crossPlugin(x: sbt.librarymanagement.ModuleID) =
compilerPlugin(x.cross(CrossVersion.full))

val compilerPlugins = List(
crossPlugin("org.typelevel" % "kind-projector" % "0.13.2"),
crossPlugin("com.github.cb372" % "scala-typed-holes" % "0.1.11"),
crossPlugin("org.polyvariant" % "better-tostring" % "0.3.15"),
compilerPlugin("com.olegpy" %% "better-monadic-for" % "0.3.1")
crossPlugin("org.polyvariant" % "better-tostring" % "0.3.15")
)

val commonSettings = List(
scalacOptions --= List("-Xfatal-warnings"),
scalacOptions += "-Ymacro-annotations",
libraryDependencies ++= List(
"org.typelevel" %% "cats-core" % "2.7.0",
"org.typelevel" %% "cats-effect" % "3.3.12",
"org.typelevel" %% "cats-tagless-macros" % "0.14.0",
"co.fs2" %% "fs2-core" % "3.2.7",
"com.github.valskalla" %% "odin-core" % "0.13.0",
"io.circe" %% "circe-core" % "0.14.1",
"dev.optics" %% "monocle-macro" % "3.1.0",
"io.circe" %% "circe-core" % "0.14.2",
"dev.optics" %% "monocle-core" % "3.1.0",
"com.disneystreaming" %% "weaver-cats" % "0.7.11" % Test,
"com.disneystreaming" %% "weaver-scalacheck" % "0.7.11" % Test
) ++ compilerPlugins,
Expand All @@ -97,9 +94,8 @@ lazy val gitlab = project
libraryDependencies ++= List(
"is.cir" %% "ciris" % "2.3.2",
"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,
"io.circe" %% "circe-parser" % "0.14.2" % Test,
"io.circe" %% "circe-literal" % "0.14.2" % Test,
"com.softwaremill.sttp.tapir" %% "tapir-core" % "0.18.0-M17",
"com.softwaremill.sttp.tapir" %% "tapir-json-circe" % "0.18.0-M17",
"com.softwaremill.sttp.tapir" %% "tapir-sttp-client" % "0.18.0-M17"
Expand All @@ -109,18 +105,17 @@ lazy val gitlab = project

lazy val bootstrap = project
.settings(
scalaVersion := "3.0.0",
scalaVersion := Scala3,
libraryDependencies ++= List(
"org.typelevel" %% "cats-core" % "2.7.0",
"org.typelevel" %% "cats-effect" % "3.3.12",
"com.kubukoz" %% "caliban-gitlab" % "0.1.0",
"com.softwaremill.sttp.client3" %% "core" % "3.3.15",
"com.softwaremill.sttp.client3" %% "circe" % "3.3.15",
"io.circe" %% "circe-core" % "0.14.1",
"io.circe" %% "circe-core" % "0.14.2",
crossPlugin("org.polyvariant" % "better-tostring" % "0.3.15")
),
publish / skip := true,
// Compile / mainClass := Some("org.polyvariant.Main"),
githubWorkflowArtifactUpload := false,
nativeImageVersion := "22.1.0",
nativeImageOptions ++= Seq(
Expand Down Expand Up @@ -195,12 +190,11 @@ lazy val pitgull =
"org.http4s" %% "http4s-blaze-server" % "0.23.11",
"org.http4s" %% "http4s-blaze-client" % "0.23.11",
"is.cir" %% "ciris" % "2.3.2",
"io.circe" %% "circe-generic-extras" % "0.14.0",
"io.scalaland" %% "chimney" % "0.6.1",
"io.chrisdavenport" %% "cats-time" % "0.4.0",
"com.github.valskalla" %% "odin-core" % "0.13.0",
"com.github.valskalla" %% "odin-slf4j" % "0.13.0",
"io.github.vigoo" %% "prox-fs2-3" % "0.7.7"
"io.github.vigoo" %% "prox-fs2-3" % "0.7.7",
"io.circe" %% "circe-literal" % "0.14.2" % Test
)
)
.dependsOn(core, gitlab)
Expand Down
9 changes: 0 additions & 9 deletions core/src/main/scala/io/pg/Prelude.scala

This file was deleted.

17 changes: 13 additions & 4 deletions core/src/main/scala/io/pg/messaging/messaging.scala
Expand Up @@ -2,11 +2,12 @@ package io.pg.messaging

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
import cats.Invariant
import cats.ApplicativeThrow

trait Publisher[F[_], -A] {
def publish(a: A): F[Unit]
Expand All @@ -16,7 +17,7 @@ final case class Processor[F[_], -A](process: fs2.Pipe[F, A, Unit])

object Processor {

def simple[F[_]: ApplicativeError[*[_], Throwable]: Logger, A](
def simple[F[_]: ApplicativeThrow: Logger, A](
f: A => F[Unit]
): Processor[F, A] =
Processor[F, A] {
Expand All @@ -35,13 +36,21 @@ object Processor {

}

@autoInvariant
trait Channel[F[_], A] extends Publisher[F, A] { self =>
trait Channel[F[_], A] extends Publisher[F, A] {
def consume: fs2.Stream[F, A]
}

object Channel {

given [F[_]]: Invariant[Channel[F, *]] with {

def imap[A, B](chan: Channel[F, A])(f: A => B)(g: B => A): Channel[F, B] = new {
def consume: fs2.Stream[F, B] = chan.consume.map(f)
def publish(b: B): F[Unit] = chan.publish(g(b))
}

}

def fromQueue[F[_]: Functor, A](q: Queue[F, A]): Channel[F, A] =
new Channel[F, A] {
def publish(a: A): F[Unit] = q.offer(a)
Expand Down
28 changes: 13 additions & 15 deletions gitlab/src/main/scala/io/pg/gitlab/Gitlab.scala
Expand Up @@ -8,7 +8,6 @@ import caliban.client.SelectionBuilder
import cats.MonadError
import cats.kernel.Eq
import cats.syntax.all._
import cats.tagless.finalAlg
import ciris.Secret
import io.odin.Logger
import io.pg.gitlab.Gitlab.MergeRequestInfo
Expand All @@ -30,14 +29,12 @@ import sttp.tapir.generic.auto._
import sttp.tapir.json.circe._
import fs2.Stream
import io.circe.{Codec => CirceCodec}
import io.circe.generic.extras.semiauto._
import io.circe.generic.extras.Configuration
import io.pg.gitlab.GitlabEndpoints.transport.MergeRequestApprovals
import monocle.macros.Lenses
import monocle.syntax.all._
import cats.Show
import io.pg.TextUtils
import cats.MonadThrow

@finalAlg
trait Gitlab[F[_]] {
def mergeRequests(projectId: Long): F[List[MergeRequestInfo]]
def acceptMergeRequest(projectId: Long, mergeRequestIid: Long): F[Unit]
Expand All @@ -47,10 +44,11 @@ trait Gitlab[F[_]] {

object Gitlab {

def apply[F[_]](using F: Gitlab[F]): Gitlab[F] = F

// VCS-specific MR information
// Not specific to the method of fetching (no graphql model references etc.)
// Fields only required according to reason (e.g. must have a numeric ID - we might loosen this later)
@Lenses
final case class MergeRequestInfo(
projectId: Long,
mergeRequestIid: Long,
Expand All @@ -62,20 +60,19 @@ object Gitlab {
)

object MergeRequestInfo {
sealed trait Status extends Product with Serializable

object Status {
case object Success extends Status
final case class Other(value: String) extends Status
enum Status {
case Success
case Other(value: String)

implicit val eq: Eq[Status] = Eq.fromUniversalEquals
}

implicit val showTrimmed: Show[MergeRequestInfo] =
MergeRequestInfo.description.modify(_.map(TextUtils.inline).map(TextUtils.trim(maxChars = 30))).apply(_).toString
_.focus(_.description).modify(_.map(TextUtils.inline).map(TextUtils.trim(maxChars = 30))).toString
}

def sttpInstance[F[_]: Logger: MonadError[*[_], Throwable]](
def sttpInstance[F[_]: Logger: MonadThrow](
baseUri: Uri,
accessToken: Secret[String]
)(
Expand Down Expand Up @@ -278,20 +275,21 @@ object GitlabEndpoints {
.in(query[Int]("approvals_required"))

object transport {
implicit val config: Configuration = Configuration.default.withSnakeCaseMemberNames

final case class ApprovalRule(id: Long, name: String, ruleType: String) {
val isMutable: Boolean = ruleType != "code_owner"
}

object ApprovalRule {
implicit val codec: CirceCodec[ApprovalRule] = deriveConfiguredCodec
// todo: use configured codec when https://github.com/circe/circe/pull/1800 is available
given CirceCodec[ApprovalRule] = CirceCodec.forProduct3("id", "name", "rule_type")(apply)(r => (r.id, r.name, r.ruleType))
}

final case class MergeRequestApprovals(approvalsRequired: Int)

object MergeRequestApprovals {
implicit val codec: CirceCodec[MergeRequestApprovals] = deriveConfiguredCodec
// todo: use configured codec when https://github.com/circe/circe/pull/1800 is available
given CirceCodec[MergeRequestApprovals] = CirceCodec.forProduct1("approvals_required")(apply)(_.approvalsRequired)
}

}
Expand Down
22 changes: 6 additions & 16 deletions gitlab/src/main/scala/io/pg/gitlab/webhook/webhook.scala
@@ -1,27 +1,17 @@
package io.pg.gitlab.webhook

import io.circe.generic.extras._
import io.circe.Codec

private object CirceConfiguration {

implicit val config: Configuration =
Configuration
.default
.withSnakeCaseMemberNames
.withSnakeCaseConstructorNames
.withDiscriminator("object_kind")
final case class WebhookEvent(project: Project, objectKind: String /* for logs */ )

object WebhookEvent {
// todo: use configured codec when https://github.com/circe/circe/pull/1800 is available
given Codec[WebhookEvent] = Codec.forProduct2("project", "object_kind")(apply)(we => (we.project, we.objectKind))
}

import CirceConfiguration._

@ConfiguredJsonCodec
final case class WebhookEvent(project: Project, objectKind: String /* for logs */ )

@ConfiguredJsonCodec
final case class Project(
id: Long
)
) derives Codec.AsObject

object Project {
val demo = Project(20190338)
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/io/pg/Application.scala
Expand Up @@ -36,15 +36,15 @@ object Application {
def resource[F[_]: Logger: Async](
config: AppConfig
): Resource[F, Application[F]] = {
implicit val projectConfigReader = ProjectConfigReader.test[F]
given ProjectConfigReader[F] = ProjectConfigReader.test[F]

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)
eventChannel.only[Event.Webhook].imap(_.value)(Event.Webhook.apply)

BlazeClientBuilder[F]
.resource
Expand Down
12 changes: 6 additions & 6 deletions src/main/scala/io/pg/Main.scala
Expand Up @@ -78,12 +78,12 @@ object Main extends IOApp {

def serve[F[_]: Async](fToIO: F ~> IO)(config: AppConfig) =
for {
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).toResource
given 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).toResource
} yield ()

def run(args: List[String]): IO[ExitCode] =
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/io/pg/MergeRequests.scala
Expand Up @@ -6,7 +6,6 @@ import cats.Show
import cats.data.EitherNel
import cats.data.NonEmptyList
import cats.implicits._
import cats.tagless.finalAlg
import fs2.Pipe
import io.odin.Logger
import io.pg.MergeRequestState
Expand All @@ -16,12 +15,13 @@ import io.pg.StateResolver
import io.pg.config.ProjectConfigReader
import io.pg.gitlab.webhook.Project

@finalAlg
trait MergeRequests[F[_]] {
def build(project: Project): F[List[MergeRequestState]]
}

object MergeRequests {
def apply[F[_]](using F: MergeRequests[F]): MergeRequests[F] = F

import scala.util.chaining._

def instance[F[_]: ProjectConfigReader: StateResolver: Monad: Logger](
Expand Down
10 changes: 4 additions & 6 deletions src/main/scala/io/pg/actions.scala
Expand Up @@ -176,7 +176,7 @@ object ProjectActions {
matchers
.traverse(_.matches(input).swap)
.swap
.leftMap(Mismatch.ManyFailed)
.leftMap(Mismatch.ManyFailed.apply)
.toEitherNel

def not[A](matcher: MatcherFunction[A]): MatcherFunction[A] = input =>
Expand Down Expand Up @@ -211,9 +211,7 @@ object ProjectActions {

}

sealed trait ProjectAction extends Product with Serializable

object ProjectAction {
final case class Merge(projectId: Long, mergeRequestIid: Long) extends ProjectAction
final case class Rebase(projectId: Long, mergeRequestIid: Long) extends ProjectAction
enum ProjectAction {
case Merge(projectId: Long, mergeRequestIid: Long)
case Rebase(projectId: Long, mergeRequestIid: Long)
}

0 comments on commit c666413

Please sign in to comment.