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
22 changes: 12 additions & 10 deletions docs/repo-specific-configuration.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Repository-specific configuration

You can add `<YOUR_REPO>/.scala-steward.conf` to configure how Scala Steward updates your repository.
You can add a configuration file `.scala-steward.conf` to configure how Scala Steward updates your repository.
The `.scala-steward.conf` configuration file can be located in the root of your repository, in `.github` directory or in `.config` directory (searched in this order).
If a configuration file exists in more than one location, only the first found file is taken into account.

```properties
# pullRequests.frequency allows to control how often or when Scala Steward
Expand Down Expand Up @@ -40,22 +42,22 @@ pullRequests.frequency = "7 days"
# the default procedure (one PR per update).
#
# Each element in the array will have the following schema:
#
#
# - name (mandatory): the name of the group, will be used for things like naming the branch
# - title (optional): if provided it will be used as the title for the PR
# - filter (mandatory): a non-empty list containing the filters to use to know
# - filter (mandatory): a non-empty list containing the filters to use to know
# if an update falls into this group.
#
# `filter` properties would have this format:
#
#
# {
# version = "major" | "minor" | "patch" | "pre-release" | "build-metadata",
# group = "{group}",
# artifact = "{artifact}"
# }
#
# For more information on the values for the `version` filter visit https://semver.org/
#
#
# Every field in a `filter` is optional but at least one must be provided.
#
# For grouping every update togeher a filter like {group = "*"} can be # provided.
Expand All @@ -69,7 +71,7 @@ pullRequests.grouping = [
{ name = "all", "title" = "Dependency updates", "filter" = [{"group" = "*"}] }
]

# pullRequests.includeMatchedLabels allows to control which labels are added to PRs
# pullRequests.includeMatchedLabels allows to control which labels are added to PRs
# via a regex check each label is checked against.
# Defaults to no regex (all labels are added) which is equivalent to ".*".
pullRequests.includeMatchedLabels = "(.*semver.*)|(commit-count:n:.*)"
Expand Down Expand Up @@ -120,10 +122,10 @@ updatePullRequests = "always" | "on-conflicts" | "never"

# If set, Scala Steward will use this message template for the commit messages and PR titles.
# Supported variables: ${artifactName}, ${currentVersion}, ${nextVersion} and ${default}
# Default: "${default}" which is equivalent to "Update ${artifactName} to ${nextVersion}"
# Default: "${default}" which is equivalent to "Update ${artifactName} to ${nextVersion}"
commits.message = "Update ${artifactName} from ${currentVersion} to ${nextVersion}"

# If true and when upgrading version in .scalafmt.conf, Scala Steward will perform scalafmt
# If true and when upgrading version in .scalafmt.conf, Scala Steward will perform scalafmt
# and add a separate commit when format changed. So you don't need reformat manually and can merge PR.
# If false, Scala Steward will not perform scalafmt, so your CI may abort when reformat needed.
# Default: true
Expand All @@ -144,7 +146,7 @@ postUpdateHooks = [{
}]

# You can override some config options for dependencies that matches the given pattern.
# Currently, "pullRequests" can be overridden.
# Currently, "pullRequests" can be overridden.
# Each pattern must have `groupId`, and may have `artifactId` and `version`.
# First-matched entry is used.
# More-specific entry should be placed before less-specific entry.
Expand Down Expand Up @@ -204,7 +206,7 @@ libraryDependencies ++= Seq(
// scala-steward:off
"com.github.pathikrit" %% "better-files" % "3.8.0",
"com.olegpy" %% "better-monadic-for" % "0.3.1",
// scala-steward:on
// scala-steward:on
"org.typelevel" %% "cats-effect" % "1.3.1", // This and subsequent will get updated
"org.typelevel" %% "cats-kernel-laws" % "1.6.1"
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package org.scalasteward.core.repoconfig

import better.files.File
import cats.syntax.all._
import cats.{Functor, MonadThrow}
import cats.{Functor, Monad, MonadThrow}
import io.circe.config.parser
import org.scalasteward.core.data.{Repo, Update}
import org.scalasteward.core.io.{FileAlg, WorkspaceAlg}
Expand All @@ -37,7 +37,10 @@ final class RepoConfigAlg[F[_]](maybeGlobalRepoConfig: Option[RepoConfig])(impli
def readRepoConfig(repo: Repo): F[ConfigParsingResult] =
for {
repoDir <- workspaceAlg.repoDir(repo)
configParsingResult <- readRepoConfigFromFile(repoDir / repoConfigBasename)
activeConfigFile <- activeConfigFile(repoDir)
configParsingResult <- activeConfigFile.fold(
F.pure[ConfigParsingResult](ConfigParsingResult.FileDoesNotExist)
)(readRepoConfigFromFile(_))
_ <- configParsingResult.fold(
F.unit,
error => logger.info(s"Failed to parse $repoConfigBasename: ${error.getMessage}"),
Expand Down Expand Up @@ -77,6 +80,29 @@ object RepoConfigAlg {
def parseRepoConfig(input: String): Either[io.circe.Error, RepoConfig] =
parser.decode[RepoConfig](input)

private val repoConfigFileSearchPath: List[List[String]] =
List(List.empty, List(".github"), List(".config"))

private def activeConfigFile[F[_]](
repoDir: File
)(implicit fileAlg: FileAlg[F], logger: Logger[F], F: Monad[F]): F[Option[File]] = {
val configFileCandidates: F[List[File]] = repoConfigFileSearchPath
.map(_ :+ repoConfigBasename)
.map(path => path.foldLeft(repoDir)(_ / _))
.filterA(fileAlg.isRegularFile)

configFileCandidates.flatMap {
case Nil => F.pure(None)
case active :: remaining =>
F.pure(active.some)
.productL(
remaining.traverse_(file =>
logger.warn(s"""Ignored config file "${file.pathAsString}"""")
)
)
}
}

def readRepoConfigFromFile[F[_]](
configFile: File
)(implicit fileAlg: FileAlg[F], F: Functor[F]): F[ConfigParsingResult] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,52 @@ class RepoConfigAlgTest extends FunSuite {
assert(clue(log).contains(startOfErrorMsg))
}

test("config file in .github/") {
val repo = Repo("test", "dot-github-config")
val repoDir = workspaceAlg.repoDir(repo).unsafeRunSync()
val rootConfigFile = repoDir / ".scala-steward.conf"
val dotGithubConfigFile = repoDir / ".github" / ".scala-steward.conf"
val initialState = MockState.empty.addFiles(dotGithubConfigFile -> "").unsafeRunSync()
val config = repoConfigAlg.readRepoConfig(repo).runA(initialState).unsafeRunSync()

assert(!fileAlg.isRegularFile(rootConfigFile).unsafeRunSync())
assert(fileAlg.isRegularFile(dotGithubConfigFile).unsafeRunSync())

assert(config.maybeRepoConfig.isDefined)
}

test("config file in .config/") {
val repo = Repo("test", "dot-config-config")
val repoDir = workspaceAlg.repoDir(repo).unsafeRunSync()
val rootConfigFile = repoDir / ".scala-steward.conf"
val dotConfigConfigFile = repoDir / ".config" / ".scala-steward.conf"
val initialState = MockState.empty.addFiles(dotConfigConfigFile -> "").unsafeRunSync()
val config = repoConfigAlg.readRepoConfig(repo).runA(initialState).unsafeRunSync()

assert(!fileAlg.isRegularFile(rootConfigFile).unsafeRunSync())
assert(fileAlg.isRegularFile(dotConfigConfigFile).unsafeRunSync())

assert(config.maybeRepoConfig.isDefined)
}

test("log warning on multiple config files") {
val repo = Repo("test", "multiple-config")
val repoDir = workspaceAlg.repoDir(repo).unsafeRunSync()
val rootConfigFile = repoDir / ".scala-steward.conf"
val dotConfigConfigFile = repoDir / ".config" / ".scala-steward.conf"
val initialState =
MockState.empty.addFiles(rootConfigFile -> "", dotConfigConfigFile -> "").unsafeRunSync()
val (state, config) = repoConfigAlg.readRepoConfig(repo).runSA(initialState).unsafeRunSync()

assert(fileAlg.isRegularFile(rootConfigFile).unsafeRunSync())
assert(fileAlg.isRegularFile(dotConfigConfigFile).unsafeRunSync())

assert(config.maybeRepoConfig.isDefined)

val log = state.trace.collectFirst { case Log((_, msg)) => msg }.getOrElse("")
assert(clue(log).contains("Ignored config file"))
}

test("configToIgnoreFurtherUpdates with single update") {
val update = ("a".g % "b".a % "c" %> "d").single
val config = RepoConfigAlg
Expand Down