Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scalafmt, Scalafix, and tpolecat #275

Merged
merged 3 commits into from
Feb 2, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ jobs:
env:
COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
sbt --client "+clean; +compile; +Test/compile; +coverage; +test; +coverageReport; +coveralls;"
sbt --client "+clean; +compile; +Test/compile; lint; +coverage; +test; +coverageReport; +coveralls;"
19 changes: 19 additions & 0 deletions .scalafix.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
rules = [
ExplicitResultTypes
LeakingImplicitClassVal
NoAutoTupling
NoValInForComprehension
OrganizeImports
ProcedureSyntax
RedundantSyntax
RemoveUnused
]

RemoveUnused {
imports = false // handled by OrganizeImports
}

OrganizeImports {
# Allign with IntelliJ IDEA so that they don't fight each other
groupedImports = Merge
}
168 changes: 168 additions & 0 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
version = "3.7.17"
runner.dialect = scala213
maxColumn = 300

// https://scalameta.org/scalafmt/docs/configuration.html#projectgit
project.git = true

fileOverride {
"glob:**/project/**.scala" {
runner.dialect = scala212
}
"glob:**/*.sbt" {
runner.dialect = sbt1
}
}

// ---------------------
// alignment
// ---------------------
align.preset = most
// align code behind -> e.g. in for ... yield
align.arrowEnumeratorGenerator = true
// multiline strings
align.stripMargin = true
assumeStandardLibraryStripMargin = true
// align also multiline statements
align.multiline = true
// don't break lines just because of alignment
align.allowOverflow = true
// align '='
align.tokens."+" = [
{
code = "="
owners = [{
parents = ["Template"]
}]
}
{
code = "="
owners = [{
regex = "Enumerator\\."
parents = ["Term\\.ForYield"]
}]
}
]
// align vals and types equally
align.treeCategory."Defn.Val" = "given/val/var/def"
align.treeCategory."Defn.Type" = "given/val/var/def"

// ---------------------
// indentation
// ---------------------
// identation of function calls
indent.callSite = 2
// indentation of "if" and "while"
indent.ctrlSite = 2
// identation of definition of parameters in cls and fce
indent.defnSite = 2
// indentation of "extends" and "with"
indent.extendSite = 2
// indent nested match and infix expressions
// this causes issues with // comments, indents them
// indent.relativeToLhsLastLine = [match, infix]
// indentation of multiline nested parentheses
binPack.indentCallSiteOnce = false
binPack.indentCallSiteSingleArg = false


// ---------------------
// indent operator
// ---------------------
// apply indentation exempts only in some cases
//indentOperator.preset = "spray"
// exempt indentation of 2nd and additional lines in special cases
indentOperator.exemptScope = all


// ---------------------
// new lines
// ---------------------
// remove line breaks, leads to horizontal code
//newlines.source = fold
// newlines around statements
newlines.topLevelStatementBlankLines = [
{
blanks = 1
}
{
minBreaks = 1
blanks = 1
}
]
// newlines after package, class, trait header if body is not trivial
newlines.topLevelBodyIfMinStatements = []
newlines.topLevelBodyMinStatements = 2
newlines.beforeTemplateBodyIfBreakInParentCtors = true
// force newline in case/if/while when the body is multiline
newlines.beforeMultiline = keep
newlines.alwaysBeforeElseAfterCurlyIf = false
// break when assignment is multiline
// newlines.forceBeforeMultilineAssign = any
// formatting of bounds of type parameters: upper <:, lower >:, view <%, and context : bounds
newlines.beforeTypeBounds = unfold
// newlines in { case ... => f() } lambdas
// newlines.beforeCurlyLambdaParams = never
// newlines.afterCurlyLambdaParams = squash
// spaces after implicit in fce parameter list
//newlines.implicitParamListModifierForce = [after]
//newlines.avoidForSimpleOverflow = [punct, tooLong, slc]
// skip newlines in the result type
newlines.avoidInResultType = true
// don't put newline before : of the result type if line overflows
newlines.sometimesBeforeColonInMethodReturnType = false
// chains of calls
newlines.selectChains = keep
// in interpolation
newlines.inInterpolation = avoid
// dangling parenteses
danglingParentheses.preset = true
danglingParentheses.exclude = []

// config style arguments
//optIn.configStyleArguments = true
//runner.optimizer.forceConfigStyleOnOffset = 80
//runner.optimizer.forceConfigStyleMinArgCount = 1


// rewrite rules
// - drop redundant braces like { } around a block
// - drop redundant parentheses like ( ) around a statement
// - sort implicit final private lazy
// - prefer for { } yield () over for (;) yield ()
// - organize imports
rewrite.rules = [RedundantBraces, RedundantParens, SortModifiers, PreferCurlyFors, Imports]
rewrite.redundantBraces.stringInterpolation = true
rewrite.imports.sort = scalastyle
rewrite.trailingCommas.style = always
// rewrite tokens to different characters
rewriteTokens = {
"⇒": "=>"
"→": "->"
"←": "<-"
}

// vertical align a line breaks
verticalMultiline.atDefnSite = true
verticalMultiline.arityThreshold = 100
verticalMultiline.newlineAfterOpenParen = true

// wrap long standalone comments
comments.wrap = standalone
comments.wrapStandaloneSlcAsSlc = true

// javadoc formatting
docstrings.style = SpaceAsterisk
docstrings.blankFirstLine = yes
docstrings.removeEmpty = true
docstrings.oneline = fold
docstrings.wrapMaxColumn = 80

// all calls in chains start on a new line
includeNoParensInSelectChains = true
// keep chains on multiple lines if already multiline
optIn.breakChainOnFirstMethodDot = true

// scala 3 config
rewrite.scala3.convertToNewSyntax = true
//rewrite.trailingCommas.style = "multiple"
38 changes: 30 additions & 8 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import org.typelevel.sbt.tpolecat.DevMode
import sbt.Keys._
import sbt._
import org.typelevel.scalacoptions._

normalizedName := "play-redis"

Expand All @@ -17,25 +19,25 @@ playVersion := "2.9.0"

libraryDependencies ++= Seq(
// play framework cache API
"com.typesafe.play" %% "play-cache" % playVersion.value % Provided,
"com.typesafe.play" %% "play-cache" % playVersion.value % Provided,
// redis connector
"io.github.rediscala" %% "rediscala" % "1.14.0-akka",
"io.github.rediscala" %% "rediscala" % "1.14.0-akka",
// test framework with mockito extension
"org.scalatest" %% "scalatest" % "3.2.17" % Test,
"org.scalamock" %% "scalamock" % "5.2.0" % Test,
"org.scalatest" %% "scalatest" % "3.2.17" % Test,
"org.scalamock" %% "scalamock" % "5.2.0" % Test,
// test module for play framework
"com.typesafe.play" %% "play-test" % playVersion.value % Test,
"com.typesafe.play" %% "play-test" % playVersion.value % Test,
// to run integration tests
"com.dimafeng" %% "testcontainers-scala-core" % "0.41.2" % Test
"com.dimafeng" %% "testcontainers-scala-core" % "0.41.2" % Test,
)

resolvers ++= Seq(
"Typesafe repository" at "https://repo.typesafe.com/typesafe/releases/"
"Typesafe repository" at "https://repo.typesafe.com/typesafe/releases/",
)

javacOptions ++= Seq("-Xlint:unchecked", "-encoding", "UTF-8")

scalacOptions ++= Seq("-deprecation", "-feature", "-unchecked")
scalacOptions ++= Seq("-deprecation", "-feature", "-unchecked", "-Ywarn-unused")

enablePlugins(CustomReleasePlugin)

Expand All @@ -44,6 +46,11 @@ coverageExcludedFiles := ".*exceptions.*"

Test / test := (Test / testOnly).toTask(" * -- -l \"org.scalatest.Ignore\"").value

semanticdbEnabled := true
semanticdbOptions += "-P:semanticdb:synthetics:on"
semanticdbVersion := scalafixSemanticdb.revision
ThisBuild / scalafixScalaBinaryVersion := CrossVersion.binaryScalaVersion(scalaVersion.value)

wartremoverWarnings ++= Warts.allBut(
Wart.Any,
Wart.AnyVal,
Expand All @@ -66,3 +73,18 @@ wartremoverWarnings ++= Warts.allBut(
Wart.TryPartial,
Wart.Var,
)

tpolecatDevModeOptions ~= { opts =>
opts.filterNot(Set(ScalacOptions.warnError))
}

Test / tpolecatExcludeOptions ++= Set(
ScalacOptions.warnValueDiscard,
ScalacOptions.warnNonUnitStatement,
)

ThisBuild / tpolecatCiModeEnvVar := "CI"
ThisBuild / tpolecatDefaultOptionsMode := DevMode

addCommandAlias("fix", "; scalafixAll; scalafmtAll; scalafmtSbt")
addCommandAlias("lint", "; scalafmtSbtCheck; scalafmtCheckAll; scalafixAll --check")
32 changes: 16 additions & 16 deletions project/CustomReleasePlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,38 +19,37 @@ object CustomReleasePlugin extends AutoPlugin {

override def requires: Plugins = ReleasePlugin && GitVersioning && Sonatype

private def customizedReleaseProcess: Seq[ReleaseStep] = {
private def customizedReleaseProcess: Seq[ReleaseStep] =
Seq[ReleaseStep](
checkSnapshotDependencies,
inquireVersions,
DocumentationUpdate.updateDocumentation,
)
}

override def projectSettings: Seq[Setting[_]] = Seq[Setting[_]](
publishMavenStyle := true,
pomIncludeRepository := { _ => false },
override def projectSettings: Seq[Setting[?]] = Seq[Setting[?]](
publishMavenStyle := true,
pomIncludeRepository := { _ => false },
// customized release process
releaseProcess := customizedReleaseProcess,
releaseProcess := customizedReleaseProcess,
// release details
homepage := Some(url("https://github.com/karelcemus/play-redis")),
licenses := Seq("Apache 2" -> url("https://www.apache.org/licenses/LICENSE-2.0")),
scmInfo := Some(
homepage := Some(url("https://github.com/karelcemus/play-redis")),
licenses := Seq("Apache 2" -> url("https://www.apache.org/licenses/LICENSE-2.0")),
scmInfo := Some(
ScmInfo(
url("https://github.com/KarelCemus/play-i18n.git"),
"scm:git@github.com:KarelCemus/play-i18n.git"
)
"scm:git@github.com:KarelCemus/play-i18n.git",
),
),
developers := List(
Developer(id = "karel.cemus", name = "Karel Cemus", email = "", url = url("https://github.com/KarelCemus/"))
developers := List(
Developer(id = "karel.cemus", name = "Karel Cemus", email = "", url = url("https://github.com/KarelCemus/")),
),
// Publish settings
publishTo := sonatypePublishToBundle.value,
publishTo := sonatypePublishToBundle.value,
// git tags without "v" prefix
SbtGit.git.gitTagToVersionNumber := { tag: String =>
if (tag matches "[0-9]+\\..*") Some(tag)
else None
}
},
)

private lazy val inquireVersions: ReleaseStep = { implicit st: State =>
Expand All @@ -65,9 +64,10 @@ object CustomReleasePlugin extends AutoPlugin {

st.log.info("Press enter to use the default value")

//flatten the Option[Option[String]] as the get returns an Option, and the value inside is an Option
// flatten the Option[Option[String]] as the get returns an Option, and the value inside is an Option
val releaseV = readVersion(suggestedReleaseV, "Release version [%s] : ", useDefs, st.get(ReleaseKeys.commandLineReleaseVersion).flatten)

st.put(ReleaseKeys.versions, (releaseV, releaseV))
}

}
10 changes: 5 additions & 5 deletions project/DocumentationUpdate.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,8 @@ object DocumentationUpdate {
private def artifactId(implicit st: State) = st.extracted.get(normalizedName)

/** SBT dependency definition */
private def sbtDependency(version: String)(implicit st: State) = {
private def sbtDependency(version: String)(implicit st: State) =
s""" "$groupId" %% "$artifactId" % "$version" """.trim
}

/** Major and minor version of Play framework */
private def playMinorVersion(implicit st: State) = {
Expand All @@ -45,16 +44,16 @@ object DocumentationUpdate {
def replacement(version: String)(implicit st: State) = s"<!-- Play $playMinorVersion -->$version<!-- / -->"
}

def updateDocumentation: ReleaseStep = ReleaseStep({ implicit st: State =>
def updateDocumentation: ReleaseStep = ReleaseStep { implicit st: State =>
val commitMessage = s"Documentation updated to version $next"
val program = List[State => State](
bumpVersionInDoc(_),
bumpLatestVersionInReadme(_),
commitVersion(commitMessage)(_)
commitVersion(commitMessage)(_),
).reduce(_ andThen _)

program(st)
})
}

private def bumpVersionInDoc(implicit st: State): State = {
val latest = vcs.latest
Expand Down Expand Up @@ -99,4 +98,5 @@ object DocumentationUpdate {
}
newState
}

}
Loading
Loading