Skip to content
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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,9 @@ jobs:
- name: Check that workflows are up to date
run: sbt githubWorkflowCheck

- name: Check scalafix/scalafmt lints
- name: Check scalafmt lints
if: matrix.java == 'temurin@25' && (matrix.scala == '3') && matrix.project == 'rootJVM' && startsWith(matrix.os, 'ubuntu')
run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' 'Test/copyResources; scalafixAll --check; all scalafmtSbtCheck scalafmtCheckAll'
run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' 'Test/copyResources; all scalafmtSbtCheck scalafmtCheckAll'

- name: Check headers and formatting
if: matrix.java == 'temurin@25' && matrix.os == 'ubuntu-latest'
Expand Down
26 changes: 0 additions & 26 deletions .scalafix.conf

This file was deleted.

11 changes: 9 additions & 2 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ danglingParentheses.preset = true
optIn.annotationNewlines = true
newlines.alwaysBeforeMultilineDef = false
runner.dialect = scala3
rewrite.rules = [RedundantBraces]
rewrite.rules = [RedundantBraces, Imports]
indentOperator.exemptScope = aloneArgOrBody
indentOperator.excludeRegex = "^(&&|\\|\\|)$"
project.excludeFilters = []
Expand All @@ -23,4 +23,11 @@ rewriteTokens = {
"⇒": "=>"
"→": "->"
"←": "<-"
}
}

rewrite.imports.sort = ascii
rewrite.imports.groups = [
["javax?\\..*"]
["scala\\..*"]
[".*"]
]
22 changes: 9 additions & 13 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import scala.scalanative.build.*

lazy val `scala-3` = "3.3.8"
lazy val `scala-3-latest` = "3.7.4"
lazy val `scala-3` = "3.9.0"
lazy val `scala-3-next` = "3.9.0"

ThisBuild / tlBaseVersion := "0.11"
ThisBuild / startYear := Some(2023)
Expand All @@ -19,9 +19,6 @@ ThisBuild / versionScheme := Some("early-semver")
ThisBuild / description := "Simple database migration tool for Scala + Postgres"
ThisBuild / homepage := Some(url("https://github.com/rolang/dumbo"))

ThisBuild / semanticdbEnabled := true
ThisBuild / semanticdbVersion := scalafixSemanticdb.revision // use Scalafix compatible version

// githubWorkflow
val defautOs = "ubuntu-latest"
val linuxOsArm = "ubuntu-24.04-arm"
Expand All @@ -42,7 +39,6 @@ ThisBuild / githubWorkflowBuildMatrixExclusions ++= Seq(
)
ThisBuild / githubWorkflowJavaVersions := testJavaVersions
ThisBuild / tlCiHeaderCheck := true
ThisBuild / tlCiScalafixCheck := false

lazy val llvmVersion = "22"
lazy val brewFormulas = Set("s2n", "utf8proc")
Expand Down Expand Up @@ -74,8 +70,8 @@ ThisBuild / githubWorkflowBuildPreamble ++= List(

ThisBuild / githubWorkflowBuild := {
WorkflowStep.Sbt(
List("Test/copyResources; scalafixAll --check; all scalafmtSbtCheck scalafmtCheckAll"),
name = Some("Check scalafix/scalafmt lints"),
List("Test/copyResources; all scalafmtSbtCheck scalafmtCheckAll"),
name = Some("Check scalafmt lints"),
cond = Some(
s"matrix.java == '${defaultJavaVersion.render}' && (matrix.scala == '3') && matrix.project == 'rootJVM' && startsWith(matrix.os, 'ubuntu')"
),
Expand Down Expand Up @@ -214,8 +210,8 @@ ThisBuild / githubWorkflowBuild += WorkflowStep.Run(
cond = Some("matrix.project == 'rootJVM' && matrix.scala == '3'"),
)

addCommandAlias("fix", "; +Test/copyResources; +scalafixAll; +scalafmtAll; scalafmtSbt")
addCommandAlias("check", "; +Test/copyResources; +scalafixAll --check; +scalafmtCheckAll; scalafmtSbtCheck")
addCommandAlias("fix", "; +Test/copyResources; +scalafmtAll; scalafmtSbt")
addCommandAlias("check", "; +Test/copyResources; +scalafmtCheckAll; scalafmtSbtCheck")

lazy val commonSettings = List(
// Headers
Expand All @@ -228,7 +224,7 @@ lazy val commonSettings = List(
|""".stripMargin
)
),
Compile / scalacOptions += "-source:future",
Compile / scalacOptions ++= (Seq("-source:future") ++ sys.env.get("CI").map(_ => Seq("-Werror")).getOrElse(Nil)),
)

lazy val root = tlCrossRootProject
Expand Down Expand Up @@ -385,8 +381,8 @@ lazy val example = project
.dependsOn(core.jvm)
.settings(commonSettings)
.settings(
scalaVersion := `scala-3-latest`,
crossScalaVersions := Seq(`scala-3-latest`),
scalaVersion := `scala-3-next`,
crossScalaVersions := Seq(`scala-3-next`),
Compile / run / fork := true,
Compile / headerCheck := Nil,
scalacOptions -= "-Werror",
Expand Down
10 changes: 7 additions & 3 deletions modules/cli/shared/src/main/scala/dumbo/cli/Arguments.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@ import java.net.URI
import scala.annotation.tailrec
import scala.util.Try

import dumbo.ConnectionConfig
import dumbo.Dumbo.defaults
import fs2.io.file.Path
import dumbo.ConnectionConfig

final case class Arguments(
commands: List[Command],
configs: List[(Config[?], String)],
flags: List[Flag],
unknown: List[String],
) {
):
def withCommand(c: Command) = copy(commands = c :: commands)
def withConfig(c: Config[?], v: String) = copy(configs = (c, v) :: configs)
def withFlag(f: Flag) = copy(flags = f :: flags)
def withUnknown(arg: String) = copy(unknown = arg :: unknown)
}
end Arguments

object Arguments:
val empty: Arguments = Arguments(Nil, Nil, Nil, Nil)
Expand Down Expand Up @@ -63,6 +63,8 @@ object Arguments:

walk(args = arguments.reverse, Arguments.empty)

end Arguments

enum Command(val keys: Set[String], val desc: String, val configs: List[Config[?]], val flags: List[Flag]):
case Help extends Command(Set("help"), "Print this usage info and exit", Nil, Nil)
case Migrate extends Command(Set("migrate"), "Migrates the database", Config.values.toList, Nil)
Expand Down Expand Up @@ -165,6 +167,8 @@ enum Config[T](val key: String, val desc: String, val parse: String => Either[St
},
)

end Config

object Config:
def helpMap(configs: List[Config[?]]) = configs.map(c => c.key -> c.desc).toMap
val helpMapAll: Map[String, String] = helpMap(Config.values.toList)
Expand Down
31 changes: 13 additions & 18 deletions modules/cli/shared/src/main/scala/dumbo/cli/Dumbo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,19 @@ import cats.effect.std.Console
import cats.effect.{ExitCode, IO, IOApp}
import dumbo.BuildInfo
import dumbo.Dumbo.defaults
import org.typelevel.otel4s.trace.Tracer.Implicits.noop
import org.typelevel.otel4s.metrics.Meter.Implicits.noop
import dumbo.logging.Implicits.consolePrettyWithTimestamp
import org.typelevel.otel4s.metrics.Meter.Implicits.noop
import org.typelevel.otel4s.trace.Tracer.Implicits.noop

object Dumbo extends IOApp {
private def printHelp(cmd: Option[Command] = None) = {
object Dumbo extends IOApp:
private def printHelp(cmd: Option[Command] = None) =
val tab = " "

def helpMapStr(m: Map[String, String]) = {
def helpMapStr(m: Map[String, String]) =
val colSize = m.keySet.maxByOption(_.length()).map(_.length()).getOrElse(0) + 3

m.map { case (k, v) => s"${k + Array.fill(colSize - k.length())(" ").mkString}$v" }
.mkString(tab, s"\n$tab", "\n")
}

val usageExample = cmd match
case None =>
Expand All @@ -36,14 +35,13 @@ object Dumbo extends IOApp {
case None => s"dumbo help [command]\nCommands\n${helpMapStr(Command.helpMap)}\n"
case Some(_) => ""

val configsHelp = {
val configsHelp =
val title = "Configuration parameters (Format: -key=value)"

cmd match
case None => Some(s"\n$title\n${helpMapStr(Config.helpMapAll)}")
case Some(c) if c.configs.nonEmpty => Some(s"\n$title\n${helpMapStr(Config.helpMap(c.configs))}")
case _ => None
}

val help =
s"""|Usage
Expand All @@ -53,22 +51,21 @@ object Dumbo extends IOApp {
|$commandsHelp${configsHelp.getOrElse("")}$usageExample""".stripMargin

Console[IO].println(help)
}

private[dumbo] def dumboFromConfigs(
configs: List[(Config[?], String)]
): Either[String, (dumbo.Dumbo[IO], dumbo.ConnectionConfig)] = {
): Either[String, (dumbo.Dumbo[IO], dumbo.ConnectionConfig)] =
def collectConfig[T](config: Config[T]): Option[Either[String, T]] =
configs.collectFirst { case (c, v) if c == config => config.parse(v) }

for {
for
uri <- collectConfig(Config.Url).toRight("Missing url").flatten
_ <- Option(uri.getScheme()) match
case None => Left(s"Missing scheme in $uri")
case Some("postgresql") => Right(())
case Some(invalid) => Left(s"Unsupported scheme $invalid")
host <- Option(uri.getHost()).toRight(s"Missing or invalid hostname in $uri")
port = { val p = uri.getPort(); if (p > -1) p else defaults.port }
port = { val p = uri.getPort(); if p > -1 then p else defaults.port }
database <- Option(uri.getPath()).flatMap(_.split("/").drop(1).headOption).toRight(s"Missing database in $uri")
user <- collectConfig(Config.User).toRight("Missing user").flatten
password <- collectConfig(Config.Password) match
Expand Down Expand Up @@ -98,7 +95,7 @@ object Dumbo extends IOApp {
password = password,
ssl = ssl,
)
} yield (
yield (
dumbo.Dumbo
.withFilesIn[IO](location)
.apply(
Expand All @@ -112,8 +109,6 @@ object Dumbo extends IOApp {
connection,
)

}

private def runMigration(options: List[(Config[?], String)]): IO[ExitCode] =
dumboFromConfigs(options) match
case Left(value) => Console[IO].errorln(s"Invalid configuration: $value").as(ExitCode.Error)
Expand All @@ -128,12 +123,11 @@ object Dumbo extends IOApp {
dumboFromConfigs(options) match
case Left(value) => Console[IO].errorln(s"Invalid configuration: $value").as(ExitCode.Error)
case Right((d, _)) =>
d.runValidationWithHistory.flatMap {
d.runValidationWithHistory.flatMap:
case Valid(_) => Console[IO].println("Validation result: ok").as(ExitCode.Success)
case Invalid(e) =>
val errs = e.toNonEmptyList.toList.map(_.getMessage())
Console[IO].errorln(s"Errors on validation: ${errs.mkString("\n", "\n", "")}").as(ExitCode.Success)
}

def run(args: List[String]): IO[ExitCode] =
val argsResult = Arguments.parse(args)
Expand Down Expand Up @@ -161,4 +155,5 @@ object Dumbo extends IOApp {
.as(ExitCode.Error)

case unknowns => Console[IO].errorln(s"Invalid arguments: ${unknowns.mkString(", ")}").as(ExitCode.Error)
}

end Dumbo
13 changes: 5 additions & 8 deletions modules/core/shared/src/main/scala/dumbo/ConnectionConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,8 @@ final case class ConnectionConfig(
ssl: ConnectionConfig.SSL = ConnectionConfig.SSL.None,
)

object ConnectionConfig {
sealed trait SSL
object SSL {
case object None extends SSL // `SSL` which indicates that SSL is not to be used
case object Trusted extends SSL // `SSL` which trusts all certificates
case object System extends SSL // `SSL` from the system default `SSLContext`
}
}
object ConnectionConfig:
enum SSL:
case None // `SSL` which indicates that SSL is not to be used
case Trusted // `SSL` which trusts all certificates
case System // `SSL` from the system default `SSLContext`
Loading
Loading