Skip to content

Commit

Permalink
Scala3 support (#974)
Browse files Browse the repository at this point in the history
- Add scala3 to all project cross versions, but mongodb.
- Mongodb does will not support scala3 due to its extensive use of macros. It won't be supported until the scala-mongodb-driver and bson libraries are released for scala3.
- Mockito is used for unit testing in a few monix connectors, so we have kept them in a separate package for scala-2.x.x.
- Pureconfig major update, which drops macros usage by manual config reader implementation.
- Add Scala3 to github-ci matrix.
  • Loading branch information
paualarco authored Nov 6, 2022
1 parent b05513e commit b8678c5
Show file tree
Hide file tree
Showing 132 changed files with 1,099 additions and 3,193 deletions.
2 changes: 1 addition & 1 deletion .github/scripts/release.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env bash

set -e
sbt ++2.13.8 ci-release
sbt ++3.1.2 ci-release
8 changes: 5 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ jobs:
fail-fast: false
matrix:
java: [8, 11]
scala: [2.12.11, 2.13.1]
scala: [2.12.17, 2.13.8, 3.1.2]
exclude:
- java: 8
scala: 2.13.1
- java: 8
scala: 3.1.2
- java: 11
scala: 2.12.11
scala: 2.12.17
steps:
- uses: actions/checkout@v2
- uses: olafurpg/setup-scala@v10
Expand Down Expand Up @@ -50,7 +52,7 @@ jobs:
run: sh start-dependencies.sh

- name: Run Functional Tests for Java ${{ matrix.java }}, Scala ${{ matrix.scala }}
run: sbt it:test
run: sbt ++${{ matrix.scala }} it:test

- name: Run Unit Tests for Java ${{ matrix.java }}, Scala ${{ matrix.scala }}
run: sbt test
Expand Down
6 changes: 3 additions & 3 deletions aws-auth/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ monix_aws: {

// Pascal case fallback
MonixAws: {
credentials {
provider: "default"
Credentials {
Provider: "default"
}
region: "eu-west-1"
Region: "eu-west-1"
}
51 changes: 32 additions & 19 deletions aws-auth/src/main/scala/monix/connect.aws.auth/MonixAwsConf.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@

package monix.connect.aws.auth

import monix.connect.aws.auth.configreader.{
CamelCaseConfigReader,
KebabConfigReader,
PascalConfigReader,
SnakeCaseConfigReader
}
import monix.eval.Task
import software.amazon.awssdk.regions.Region
import pureconfig._
import pureconfig.error.{ConfigReaderException, ConfigReaderFailures}
import pureconfig.generic.ProductHint
import pureconfig.generic.auto._
import pureconfig.{NamingConvention, _}
import pureconfig.error.ConfigReaderFailures
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider

import java.io.File
Expand Down Expand Up @@ -72,13 +76,16 @@ object MonixAwsConf {

private[auth] final case class AppConf(monixAws: MonixAwsConf)

implicit val credentialsProviderReader: ConfigReader[AwsCredentialsProvider] =
ConfigReader[AwsCredentialsConf].map(_.credentialsProvider)
implicit val providerReader: ConfigReader[Providers.Provider] = ConfigReader[String].map(Providers.fromString)
implicit val regionReader: ConfigReader[Region] = ConfigReader[String].map(Region.of)
implicit val uriReader: ConfigReader[URI] = ConfigReader[String].map(URI.create)
val customHint: NamingConvention => ProductHint[AppConf] = namingConvention =>
ProductHint(ConfigFieldMapping(CamelCase, namingConvention), useDefaultArgs = false, allowUnknownKeys = true)
private def withConfigReader[A](namingConvention: NamingConvention)(f: ConfigReader[AppConf] => Task[A]): Task[A] = {
val derivedConfigReaderTask = namingConvention match {
case CamelCase => Task.pure(CamelCaseConfigReader.appConfConfigReader)
case SnakeCase => Task.pure(SnakeCaseConfigReader.appConfConfigReader)
case PascalCase => Task.pure(PascalConfigReader.appConfConfigReader)
case KebabCase => Task.pure(KebabConfigReader.appConfConfigReader)
case _ => Task.raiseError(new IllegalArgumentException(s"Naming convention $namingConvention not supported."))
}
derivedConfigReaderTask.flatMap(f)
}

/**
* Loads the aws auth configuration from the config file with the specified naming
Expand All @@ -91,10 +98,13 @@ object MonixAwsConf {
*
*/
def load(namingConvention: NamingConvention = KebabCase): Task[MonixAwsConf] = {
implicit val hint: ProductHint[AppConf] = customHint(namingConvention)
Task
.fromEither[ConfigReaderFailures, AppConf] { ConfigReaderException(_) }(ConfigSource.default.load[AppConf])
.map(_.monixAws)
withConfigReader(namingConvention) { configReader =>
Task
.fromEither[ConfigReaderFailures, AppConf] { ex =>
new IllegalArgumentException(s"Cannot convert configuration to class, failures are: ${ex.prettyPrint(1)}")
}(ConfigSource.default.load[AppConf](configReader))
.map(_.monixAws)
}
}

/**
Expand All @@ -108,10 +118,13 @@ object MonixAwsConf {
*
*/
def file(file: File, namingConvention: NamingConvention = KebabCase): Task[MonixAwsConf] = {
implicit val hint: ProductHint[AppConf] = customHint(namingConvention)
Task
.fromEither[ConfigReaderFailures, AppConf] { ConfigReaderException(_) }(ConfigSource.file(file).load[AppConf])
.map(_.monixAws)
withConfigReader(namingConvention) { configReader =>
Task
.fromEither[ConfigReaderFailures, AppConf] { ex =>
new IllegalArgumentException(s"Cannot convert configuration to class, failures are: ${ex.prettyPrint(1)}")
}(ConfigSource.file(file).load[AppConf](configReader))
.map(_.monixAws)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2020-2021 by The Monix Connect Project Developers.
* See the project homepage at: https://connect.monix.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package monix.connect.aws.auth.configreader

import monix.connect.aws.auth.MonixAwsConf.AppConf
import monix.connect.aws.auth.{AwsCredentialsConf, HttpClientConf, MonixAwsConf, StaticCredentialsConf}
import pureconfig.ConfigReader
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider

private[auth] trait BaseConfigReader {

def cased(sequence: String*): String
private[auth] implicit val staticCreedsConfConfigReader: ConfigReader[StaticCredentialsConf] =
ConfigReader.forProduct3(cased("access", "key", "id"), cased("secret", "access", "key"), cased("session", "token"))(
StaticCredentialsConf(_, _, _))
private[auth] implicit val awsCredentialsConfConfigReader: ConfigReader[AwsCredentialsConf] =
ConfigReader.forProduct3(cased("provider"), cased("profile", "name"), cased("static"))(AwsCredentialsConf(_, _, _))
private[auth] implicit val credentialsProviderReader: ConfigReader[AwsCredentialsProvider] =
ConfigReader[AwsCredentialsConf].map(_.credentialsProvider)
private[auth] implicit val httpClientConfConfigReader: ConfigReader[HttpClientConf] = ConfigReader.forProduct8(
cased("max", "concurrency"),
cased("max", "pending", "connection", "acquires"),
cased("connection", "acquisition", "timeout"),
cased("connection", "max", "idle", "time"),
cased("connection", "time", "to", "live"),
cased("use", "idle", "connection", "reaper"),
cased("read", "timeout"),
cased("write", "timeout")
)(HttpClientConf(_, _, _, _, _, _, _, _))
private[auth] implicit val monixAwsConfConfigReader: ConfigReader[MonixAwsConf] =
ConfigReader.forProduct4(cased("region"), cased("credentials"), cased("endpoint"), cased("http", "client"))(
MonixAwsConf(_, _, _, _))
private[auth] implicit val appConfConfigReader: ConfigReader[AppConf] =
ConfigReader.forProduct1(cased("monix", "aws"))(AppConf(_))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2020-2021 by The Monix Connect Project Developers.
* See the project homepage at: https://connect.monix.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package monix.connect.aws.auth.configreader

import pureconfig.CamelCase

private[auth] object CamelCaseConfigReader extends BaseConfigReader {
override def cased(sequence: String*): String = CamelCase.fromTokens(sequence)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2020-2021 by The Monix Connect Project Developers.
* See the project homepage at: https://connect.monix.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package monix.connect.aws.auth.configreader

import pureconfig.KebabCase

private[auth] object KebabConfigReader extends BaseConfigReader {
override def cased(sequence: String*): String = KebabCase.fromTokens(sequence)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2020-2021 by The Monix Connect Project Developers.
* See the project homepage at: https://connect.monix.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package monix.connect.aws.auth.configreader

import pureconfig.PascalCase

private[auth] object PascalConfigReader extends BaseConfigReader {
override def cased(sequence: String*): String = PascalCase.fromTokens(sequence)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2020-2021 by The Monix Connect Project Developers.
* See the project homepage at: https://connect.monix.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package monix.connect.aws.auth.configreader

import pureconfig.SnakeCase

private[auth] object SnakeCaseConfigReader extends BaseConfigReader {
override def cased(sequence: String*): String = SnakeCase.fromTokens(sequence)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2020-2021 by The Monix Connect Project Developers.
* See the project homepage at: https://connect.monix.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package monix.connect.aws.auth

import pureconfig.ConfigReader
import software.amazon.awssdk.regions.Region

import java.net.URI

package object configreader {

private[configreader] implicit val providerReader: ConfigReader[Providers.Provider] =
ConfigReader[String].map(Providers.fromString)
private[configreader] implicit val regionReader: ConfigReader[Region] = ConfigReader[String].map(Region.of)
private[configreader] implicit val uriReader: ConfigReader[URI] = ConfigReader[String].map(URI.create)

}
8 changes: 4 additions & 4 deletions aws-auth/src/test/resources/PascalCase.conf
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
MonixAws: {
credentials {
provider: "default"
Credentials {
Provider: "default"
}
region: "eu-west-1"
endpoint: "PascalCase:12345"
Region: "eu-west-1"
Endpoint: "PascalCase:12345"
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import pureconfig.ConfigSource
import pureconfig.error.ConfigReaderException
import pureconfig.generic.auto._
import MonixAwsConf._
import monix.connect.aws.auth.configreader.KebabConfigReader
import software.amazon.awssdk.auth.credentials.{
AnonymousCredentialsProvider,
AwsSessionCredentials,
Expand All @@ -37,8 +36,8 @@ import software.amazon.awssdk.auth.credentials.{
import scala.util.Try

class AwsCredentialsConfSpec extends AnyFlatSpec with Matchers {

s"$AwsCredentialsConf" should "allow to set aws default credentials" in {
import KebabConfigReader._
s"AwsCredentialsConf" should "allow to set aws default credentials" in {
//given
val configSource = ConfigSource.string(
"" +
Expand Down
Loading

0 comments on commit b8678c5

Please sign in to comment.