Skip to content

Commit

Permalink
Migrate to scala 3 (#91)
Browse files Browse the repository at this point in the history
Migrate to Scala 3
  • Loading branch information
geirolz authored Feb 15, 2024
1 parent fba810d commit e17a19c
Show file tree
Hide file tree
Showing 95 changed files with 1,665 additions and 2,647 deletions.
16 changes: 7 additions & 9 deletions .github/workflows/cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ on:

# env variables
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }}
SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
Expand All @@ -28,12 +27,9 @@ jobs:
matrix:
# supported scala versions
include:
- scala: 2.13.12
name: Scala2_13
test-tasks: scalafmtCheck test gen-doc
- scala: 3.3.1
name: Scala3_3
test-tasks: test
- scala: 3.4.0
name: Scala3_4
test-tasks: scalafmtCheck gen-doc coverage test coverageReport

steps:
- uses: actions/checkout@v3
Expand Down Expand Up @@ -65,8 +61,10 @@ jobs:
run: sbt ++${{ matrix.scala }} mimaReportBinaryIssues

#----------- COVERAGE -----------
- name: Submit Code Coverage
run: bash <(curl -s https://codecov.io/bash)
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

deploy:
runs-on: ubuntu-latest
Expand Down
9 changes: 3 additions & 6 deletions .mergify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ pull_request_rules:
- "#approved-reviews-by>=1"
- check-success=codecov/patch
- check-success=codecov/project
- check-success=build (Scala2_13)
- check-success=build (Scala3_3)
- check-success=build (Scala3_4)
- base=main
- label!=work-in-progress
actions:
Expand All @@ -14,17 +13,15 @@ pull_request_rules:
- name: automatic merge for master when CI passes and author is steward
conditions:
- author=scala-steward-geirolz[bot]
- check-success=build (Scala2_13)
- check-success=build (Scala3_3)
- check-success=build (Scala3_4)
- base=main
actions:
merge:
method: rebase
- name: automatic merge for master when CI passes and author is dependabot
conditions:
- author=dependabot[bot]
- check-success=build (Scala2_13)
- check-success=build (Scala3_3)
- check-success=build (Scala3_4)
- base=main
actions:
merge:
Expand Down
8 changes: 1 addition & 7 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
version = 3.7.17
encoding = "UTF-8"
runner.dialect = "scala213source3"
runner.dialect = "scala3"
maxColumn = 150

project.git = true
Expand Down Expand Up @@ -32,9 +32,3 @@ docstrings.blankFirstLine = no
docstrings.forceBlankLineBefore = true

spaces.inImportCurlyBraces = false

fileOverride {
"glob:**/scala-3*/**" {
runner.dialect = scala3
}
}
78 changes: 36 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,31 +70,27 @@ libraryDependencies += "com.github.geirolz" %% "toolkit" % "0.0.11"
```scala
import cats.Show
import cats.effect.{Resource, IO}
import com.geirolz.app.toolkit.{App, SimpleAppInfo}
import com.geirolz.app.toolkit.logger.ToolkitLogger
import com.geirolz.app.toolkit.*
import com.geirolz.app.toolkit.logger.ConsoleLogger
import com.geirolz.app.toolkit.novalues.NoResources

// Define config
case class Config(host: String, port: Int)

object Config {
implicit val show: Show[Config] = Show.fromToString
}
object Config:
given Show[Config] = Show.fromToString

// Define service dependencies
case class AppDependencyServices(kafkaConsumer: KafkaConsumer[IO])

object AppDependencyServices {
def resource(res: App.Resources[SimpleAppInfo[String], ToolkitLogger[IO], Config, NoResources]): Resource[IO, AppDependencyServices] =
Resource.pure(AppDependencyServices(KafkaConsumer.fake))
}
object AppDependencyServices:
def resource(using AppContext.NoDepsAndRes[SimpleAppInfo[String], ConsoleLogger[IO], Config]): Resource[IO, AppDependencyServices] =
Resource.pure(AppDependencyServices(KafkaConsumer.fake))

// A stubbed kafka consumer
trait KafkaConsumer[F[_]] {
trait KafkaConsumer[F[_]]:
def consumeFrom(name: String): fs2.Stream[F, KafkaConsumer.KafkaRecord]
}

object KafkaConsumer {
object KafkaConsumer:

import scala.concurrent.duration.DurationInt

Expand All @@ -105,43 +101,41 @@ object KafkaConsumer {
fs2.Stream
.eval(IO.randomUUID.map(t => KafkaRecord(t.toString)).flatTap(_ => IO.sleep(5.seconds)))
.repeat
}
```

3. **Build Your Application:** Build your application using the Toolkit DSL and execute it. Toolkit
takes care of managing resources, handling dependencies, and orchestrating the execution of your application logic.

```scala
import cats.effect.{ExitCode, IO, IOApp}
import com.geirolz.app.toolkit.{App, SimpleAppInfo}
import com.geirolz.app.toolkit.logger.ToolkitLogger

object Main extends IOApp {
override def run(args: List[String]): IO[ExitCode] =
App[IO]
.withInfo(
SimpleAppInfo.string(
name = "toolkit",
version = "0.0.1",
scalaVersion = "2.13.10",
sbtVersion = "1.8.0"
import com.geirolz.app.toolkit.*
import com.geirolz.app.toolkit.logger.Logger

object Main extends IOApp:
override def run(args: List[String]): IO[ExitCode] =
App[IO]
.withInfo(
SimpleAppInfo.string(
name = "toolkit",
version = "0.0.1",
scalaVersion = "2.13.10",
sbtVersion = "1.8.0"
)
)
.withConsoleLogger()
.withConfigF(IO.pure(Config("localhost", 8080)))
.dependsOn(AppDependencyServices.resource)
.beforeProviding(ctx.logger.info("CUSTOM PRE-PROVIDING"))
.provideOne(
// Kafka consumer
ctx.dependencies.kafkaConsumer
.consumeFrom("test-topic")
.evalTap(record => ctx.logger.info(s"Received record $record"))
.compile
.drain
)
)
.withLogger(ToolkitLogger.console[IO](_))
.withConfigLoader(_ => IO.pure(Config("localhost", 8080)))
.dependsOn(AppDependencyServices.resource(_))
.beforeProviding(_.logger.info("CUSTOM PRE-PROVIDING"))
.provideOne(deps =>
// Kafka consumer
deps.dependencies.kafkaConsumer
.consumeFrom("test-topic")
.evalTap(record => deps.logger.info(s"Received record $record"))
.compile
.drain
)
.onFinalize(_.logger.info("CUSTOM END"))
.run(args)
}
.onFinalize(ctx.logger.info("CUSTOM END"))
.run(args)
```

Check a full example [here](https://github.com/geirolz/toolkit/tree/main/examples)
Expand Down
107 changes: 19 additions & 88 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ import sbt.project
lazy val prjName = "toolkit"
lazy val prjDescription = "A small toolkit to build functional app with managed resources"
lazy val org = "com.github.geirolz"
lazy val scala213 = "2.13.12"
lazy val scala32 = "3.3.1"
lazy val supportedScalaVersions = List(scala213, scala32)
lazy val scala34 = "3.4.0"
lazy val supportedScalaVersions = List(scala34)

//## global project to no publish ##
val copyReadMe = taskKey[Unit]("Copy generated README to main folder.")
Expand Down Expand Up @@ -35,23 +34,17 @@ lazy val root: Project = project
.settings(
copyReadMe := IO.copyFile(file("docs/compiled/README.md"), file("README.md"))
)
.aggregate(core, docs, config, testing, log4cats, odin, pureconfig, fly4s)
.aggregate(core, docs, testing, log4cats, odin, pureconfig, fly4s)

lazy val docs: Project =
project
.in(file("docs"))
.enablePlugins(MdocPlugin)
.dependsOn(core, config, log4cats, odin, pureconfig, fly4s)
.dependsOn(core, log4cats, odin, pureconfig, fly4s)
.settings(
baseSettings,
noPublishSettings,
libraryDependencies ++= Seq(
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, 13)) => ProjectDependencies.Docs.dedicated_2_13
case Some((3, _)) => ProjectDependencies.Docs.dedicated_3_2
case _ => Nil
}
).flatten,
libraryDependencies ++= ProjectDependencies.Docs.dedicated,
// config
scalacOptions --= Seq("-Werror", "-Xfatal-warnings"),
mdocIn := file("docs/source"),
Expand All @@ -72,14 +65,6 @@ lazy val core: Project =
libraryDependencies ++= ProjectDependencies.Core.dedicated
).dependsOn(testing)

lazy val config: Project =
module("config")(
folder = "./config",
publishAs = Some(subProjectName("config"))
).settings(
libraryDependencies ++= ProjectDependencies.Config.dedicated
)

lazy val testing: Project =
module("testing")(
folder = "./testing",
Expand All @@ -96,13 +81,7 @@ lazy val examples: Project = {
.settings(
noPublishSettings,
Compile / mainClass := Some(s"$appPackage.AppMain"),
libraryDependencies ++= {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, 13)) => ProjectDependencies.Examples.dedicated_2_13
case Some((3, _)) => ProjectDependencies.Examples.dedicated_3_2
case _ => Nil
}
},
libraryDependencies ++= ProjectDependencies.Examples.dedicated,
buildInfoKeys ++= List[BuildInfoKey](
name,
description,
Expand All @@ -118,7 +97,7 @@ lazy val examples: Project = {
),
buildInfoPackage := appPackage
)
.dependsOn(core, config, log4cats, pureconfig)
.dependsOn(core, log4cats, pureconfig)
}

// integrations
Expand All @@ -145,7 +124,7 @@ lazy val pureconfig: Project =
module("pureconfig")(
folder = s"$integrationsFolder/pureconfig",
publishAs = Some(subProjectName("pureconfig"))
).dependsOn(core, config)
).dependsOn(core)
.settings(
libraryDependencies ++= ProjectDependencies.Integrations.Pureconfig.dedicated
)
Expand Down Expand Up @@ -214,75 +193,27 @@ lazy val baseSettings: Seq[Def.Setting[_]] = Seq(
versionScheme := Some("early-semver"),
// dependencies
resolvers ++= ProjectResolvers.all,
libraryDependencies ++= ProjectDependencies.common ++ {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, 13)) => ProjectDependencies.Plugins.compilerPluginsFor2_13
case Some((3, _)) => ProjectDependencies.Plugins.compilerPluginsFor3
case _ => Nil
}
}
libraryDependencies ++= Seq(
ProjectDependencies.common,
ProjectDependencies.Plugins.compilerPlugins
).flatten
)

def scalacSettings(scalaVersion: String): Seq[String] =
Seq(
// "-Xlog-implicits",
// "-deprecation", // Emit warning and location for usages of deprecated APIs.
"-encoding",
"utf-8", // Specify character encoding used by source files.
"-explain",
"-deprecation",
"-feature", // Emit warning and location for usages of features that should be imported explicitly.
"-language:existentials", // Existential types (besides wildcard types) can be written and inferred
// "-language:experimental.macros", // Allow macro definition (besides implementation and application)
"-language:higherKinds", // Allow higher-kinded types
"-language:implicitConversions", // Allow definition of implicit functions called views
"-language:dynamics"
) ++ {
CrossVersion.partialVersion(scalaVersion) match {
case Some((3, _)) =>
Seq(
"-Ykind-projector",
"-explain-types", // Explain type errors in more detail.
"-Xfatal-warnings" // Fail the compilation if there are any warnings.
)
case Some((2, 13)) =>
Seq(
"-explaintypes", // Explain type errors in more detail.
"-unchecked", // Enable additional warnings where generated code depends on assumptions.
"-Xcheckinit", // Wrap field accessors to throw an exception on uninitialized access.
"-Xfatal-warnings", // Fail the compilation if there are any warnings.
"-Xlint:adapted-args", // Warn if an argument list is modified to match the receiver.
"-Xlint:constant", // Evaluation of a constant arithmetic expression results in an error.
"-Xlint:delayedinit-select", // Selecting member of DelayedInit.
"-Xlint:doc-detached", // A Scaladoc comment appears to be detached from its element.
"-Xlint:inaccessible", // Warn about inaccessible types in method signatures.
"-Xlint:infer-any", // Warn when a type argument is inferred to be `Any`.
"-Xlint:missing-interpolator", // A string literal appears to be missing an interpolator id.
"-Xlint:nullary-unit", // Warn when nullary methods return Unit.
"-Xlint:option-implicit", // Option.apply used implicit view.
"-Xlint:package-object-classes", // Class or object defined in package object.
"-Xlint:poly-implicit-overload", // Parameterized overloaded implicit methods are not visible as view bounds.
"-Xlint:private-shadow", // A private field (or class parameter) shadows a superclass field.
"-Xlint:stars-align", // Pattern sequence wildcard must align with sequence component.
"-Xlint:type-parameter-shadow", // A local type parameter shadows a type already in scope.
"-Ywarn-dead-code", // Warn when dead code is identified.
"-Ywarn-extra-implicit", // Warn when more than one implicit parameter section is defined.
"-Xlint:nullary-unit", // Warn when nullary methods return Unit.
"-Ywarn-numeric-widen", // Warn when numerics are widened.
"-Ywarn-value-discard", // Warn when non-Unit expression results are unused.
"-Xlint:inaccessible", // Warn about inaccessible types in method signatures.
"-Xlint:infer-any", // Warn when a type argument is inferred to be `Any`.
"-Ywarn-unused:implicits", // Warn if an implicit parameter is unused.
"-Ywarn-unused:imports", // Warn if an import selector is not referenced.
"-Ywarn-unused:locals", // Warn if a local definition is unused.
"-Ywarn-unused:explicits", // Warn if a explicit value parameter is unused.
"-Ywarn-unused:patvars", // Warn if a variable bound in a pattern is unused.
"-Ywarn-unused:privates", // Warn if a private member is unused.
"-Ywarn-macros:after", // Tells the compiler to make the unused checks after macro expansion
"-Xsource:3",
"-P:kind-projector:underscore-placeholders"
)
case _ => Nil
}
}
"-language:dynamics",
"-Ykind-projector",
"-explain-types", // Explain type errors in more detail.
"-Xfatal-warnings" // Fail the compilation if there are any warnings.
)

//=============================== ALIASES ===============================
addCommandAlias("check", "scalafmtAll;clean;coverage;test;coverageAggregate")
Expand Down

This file was deleted.

Loading

0 comments on commit e17a19c

Please sign in to comment.