diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml new file mode 100644 index 0000000..178d5cb --- /dev/null +++ b/.github/workflows/checks.yml @@ -0,0 +1,33 @@ +name: Code checks +on: + pull_request: + branches: [ "main" ] +jobs: + scalafmt-lint: + name: Scalafmt lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 1 + - uses: jrouly/scalafmt-native-action@v4 + + scalafix-lint: + name: Scalafix lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Setup JDK + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 21 + cache: sbt + + - name: Setup SBT + uses: sbt/setup-sbt@v1 + + - run: sbt 'scalafixAll --check' diff --git a/.scalafix.conf b/.scalafix.conf new file mode 100644 index 0000000..7b1e65a --- /dev/null +++ b/.scalafix.conf @@ -0,0 +1,7 @@ +rules = [ + RemoveUnused + ExplicitResultTypes + ProcedureSyntax + RedundantSyntax +] +ExplicitResultTypes.memberVisibility = [Public] diff --git a/.scalafmt.conf b/.scalafmt.conf new file mode 100644 index 0000000..72988b1 --- /dev/null +++ b/.scalafmt.conf @@ -0,0 +1,7 @@ +version = 3.8.6 +runner.dialect = scala36 +maxColumn = 100 +align.preset=none +rewrite.trailingCommas.style = always +newlines.selectChains.style = keep +newlines.selectChains.classicKeepAfterFirstBreak = true diff --git a/README.md b/README.md index 08195d3..e91e46a 100644 --- a/README.md +++ b/README.md @@ -28,3 +28,8 @@ $ ./jelly-cli --help - The binary will be available at `./target/graalvm-native-image/jelly-cli`. Alternatively, you can use the utility with your JVM (no ahead-of-time compilation), by running `sbt run`. + +## Developer notes + +Run `sbt fixAll` before committing. Your code should be formatted and free of warnings. +The CI checks will not pass if this is not the case. diff --git a/build.sbt b/build.sbt index 21d0d67..09be481 100644 --- a/build.sbt +++ b/build.sbt @@ -1,5 +1,4 @@ -ThisBuild / version := "0.1.0-SNAPSHOT" - +ThisBuild / semanticdbEnabled := true ThisBuild / scalaVersion := "3.6.4" resolvers += @@ -8,6 +7,8 @@ resolvers += lazy val jenaV = "5.3.0" lazy val jellyV = "2.8.0+14-4181e89a-SNAPSHOT" +addCommandAlias("fixAll", "scalafixAll; scalafmtAll") + def isDevBuild: Boolean = sys.env.get("DEV_BUILD").exists(s => s != "0" && s != "false") @@ -25,6 +26,14 @@ lazy val root = (project in file(".")) "com.github.alexarchambault" %% "case-app" % "2.1.0-M30", "org.scalatest" %% "scalatest" % "3.2.19" % Test, ), + scalacOptions ++= Seq( + "-Wunused:imports", + "-Werror", + "-feature", + "-deprecation", + "-unchecked", + "-explain", + ), buildInfoKeys := Seq[BuildInfoKey]( version, scalaVersion, diff --git a/project/plugins.sbt b/project/plugins.sbt index 9abd225..4a1ca1c 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,3 +1,5 @@ addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.13.1") addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.9.3") addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.11.1") +addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.14.0") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.4") diff --git a/src/main/scala/eu/neverblink/jelly/cli/App.scala b/src/main/scala/eu/neverblink/jelly/cli/App.scala index 7973cf6..ef394a5 100644 --- a/src/main/scala/eu/neverblink/jelly/cli/App.scala +++ b/src/main/scala/eu/neverblink/jelly/cli/App.scala @@ -3,9 +3,8 @@ package eu.neverblink.jelly.cli import caseapp.* import eu.neverblink.jelly.cli.command.* -/** - * Main entrypoint. - */ +/** Main entrypoint. + */ object App extends CommandsEntryPoint: override def progName: String = "jelly-cli" diff --git a/src/main/scala/eu/neverblink/jelly/cli/JellyCommand.scala b/src/main/scala/eu/neverblink/jelly/cli/JellyCommand.scala index 118b818..9bb527e 100644 --- a/src/main/scala/eu/neverblink/jelly/cli/JellyCommand.scala +++ b/src/main/scala/eu/neverblink/jelly/cli/JellyCommand.scala @@ -9,17 +9,17 @@ import scala.compiletime.uninitialized object JellyCommand: val emptyRemainingArgs: RemainingArgs = RemainingArgs(Seq.empty, Seq.empty) -abstract class JellyCommand[T : {Parser, Help}] extends Command[T]: +abstract class JellyCommand[T: {Parser, Help}] extends Command[T]: private var isTest = false private var out = System.out private var err = System.err private var osOut: ByteArrayOutputStream = uninitialized private var osErr: ByteArrayOutputStream = uninitialized - /** - * Enable the "test mode" which captures stdout, stderr, exit code, and so on. - * @param test true to enable, false to disable - */ + /** Enable the "test mode" which captures stdout, stderr, exit code, and so on. + * @param test + * true to enable, false to disable + */ def testMode(test: Boolean): Unit = this.isTest = test if test then @@ -47,13 +47,16 @@ abstract class JellyCommand[T : {Parser, Help}] extends Command[T]: s else throw new IllegalStateException("Not in test mode") - /** - * Run the command in test mode, capturing stdout and stderr. - * @param options the command options - * @param remainingArgs the remaining arguments - * @throws ExitError if the command exits - * @return (stdout, stderr) - */ + /** Run the command in test mode, capturing stdout and stderr. + * @param options + * the command options + * @param remainingArgs + * the remaining arguments + * @throws ExitError + * if the command exits + * @return + * (stdout, stderr) + */ @throws[ExitError] def runTest(options: T, remainingArgs: RemainingArgs = emptyRemainingArgs): (String, String) = if !isTest then testMode(true) diff --git a/src/main/scala/eu/neverblink/jelly/cli/command/FoolAround.scala b/src/main/scala/eu/neverblink/jelly/cli/command/FoolAround.scala index 8425f8b..9f1b2f2 100644 --- a/src/main/scala/eu/neverblink/jelly/cli/command/FoolAround.scala +++ b/src/main/scala/eu/neverblink/jelly/cli/command/FoolAround.scala @@ -4,13 +4,12 @@ import caseapp.* import eu.neverblink.jelly.cli.JellyCommand case class FoolAroundOptions( - @HelpMessage("What to say") - say: String = "Hello, World!" + @HelpMessage("What to say") + say: String = "Hello, World!", ) -/** - * "foo-bar" kind of command. - */ +/** "foo-bar" kind of command. + */ object FoolAround extends JellyCommand[FoolAroundOptions]: // https://alexarchambault.github.io/case-app/commands/ override def names: List[List[String]] = List( diff --git a/src/main/scala/eu/neverblink/jelly/cli/command/Version.scala b/src/main/scala/eu/neverblink/jelly/cli/command/Version.scala index 5c265ae..29fe4f0 100644 --- a/src/main/scala/eu/neverblink/jelly/cli/command/Version.scala +++ b/src/main/scala/eu/neverblink/jelly/cli/command/Version.scala @@ -16,10 +16,10 @@ object Version extends JellyCommand[VersionOptions]: .find(_.startsWith("org.apache.jena:jena-core:")).get.split(":")(2) val jellyV = BuildInfo.libraryDependencies .find(_.startsWith("eu.ostrzyciel.jelly:jelly-jena:")).get.split(":")(2) - printLine( - f"""jelly-cli ${BuildInfo.version} + printLine(f""" + |jelly-cli ${BuildInfo.version} |---------------------------------------------- |Jelly-JVM $jellyV |Apache Jena $jenaV |JVM ${System.getProperty("java.vm.name")} ${System.getProperty("java.vm.version")} - |""".stripMargin) + |""".stripMargin.trim) diff --git a/src/test/scala/eu/neverblink/jelly/cli/command/VersionSpec.scala b/src/test/scala/eu/neverblink/jelly/cli/command/VersionSpec.scala index fc4f9f9..3059933 100644 --- a/src/test/scala/eu/neverblink/jelly/cli/command/VersionSpec.scala +++ b/src/test/scala/eu/neverblink/jelly/cli/command/VersionSpec.scala @@ -7,8 +7,8 @@ class VersionSpec extends AnyWordSpec, Matchers: "version command" should { "print something" in { val (out, err) = Version.runTest(VersionOptions()) - out should startWith ("jelly-cli") - out should include ("Jelly-JVM") - out should include ("Apache Jena") + out should startWith("jelly-cli") + out should include("Jelly-JVM") + out should include("Apache Jena") } }