Skip to content

Commit 37a29f4

Browse files
Merge pull request #1217 from taisukeoe/add-on-compile-mode
add --triggered flag to load overlay section in .scalafix.conf
2 parents 693ed5a + ac0e1c3 commit 37a29f4

File tree

7 files changed

+152
-3
lines changed

7 files changed

+152
-3
lines changed

scalafix-cli/src/main/scala/scalafix/internal/interfaces/ScalafixArgumentsImpl.scala

+2
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ final case class ScalafixArgumentsImpl(args: Args = Args.default)
119119
copy(args = args.copy(stdout = true))
120120
case ScalafixMainMode.AUTO_SUPPRESS_LINTER_ERRORS =>
121121
copy(args = args.copy(autoSuppressLinterErrors = true))
122+
case ScalafixMainMode.IN_PLACE_TRIGGERED =>
123+
copy(args = args.copy(triggered = true))
122124
}
123125

124126
override def withParsedArguments(

scalafix-cli/src/main/scala/scalafix/internal/v1/Args.scala

+22-2
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ case class Args(
8484
"configured in .scalafix.conf or via --rules"
8585
)
8686
syntactic: Boolean = false,
87+
@Description(
88+
"Overlay the default rules & rule settings in .scalafix.conf with the `triggered` section"
89+
)
90+
triggered: Boolean = false,
8791
@Description("Print out additional diagnostics while running scalafix.")
8892
verbose: Boolean = false,
8993
@Description("Print out this help message and exit")
@@ -245,9 +249,22 @@ case class Args(
245249
RuleDecoder.decoder(ruleDecoderSettings.withConfig(scalafixConfig))
246250
}
247251

252+
// With a --triggered flag, looking for settings in triggered block first, and fallback to standard settings.
253+
def maybeOverlaidConfWithTriggered(base: Conf): Conf =
254+
if (triggered)
255+
ScalafixConfOps.overlay(base, "triggered")
256+
else
257+
base
258+
248259
def rulesConf(base: () => Conf): Conf = {
249260
if (rules.isEmpty) {
250-
ConfGet.getKey(base(), "rules" :: "rule" :: Nil) match {
261+
val rulesInConf =
262+
ConfGet.getKey(
263+
maybeOverlaidConfWithTriggered(base()),
264+
"rules" :: "rule" :: Nil
265+
)
266+
267+
rulesInConf match {
251268
case Some(c) => c
252269
case _ => Conf.Lst(Nil)
253270
}
@@ -260,10 +277,13 @@ case class Args(
260277
base: Conf,
261278
scalafixConfig: ScalafixConfig
262279
): Configured[Rules] = {
280+
val targetConf = maybeOverlaidConfWithTriggered(base)
281+
263282
val rulesConf = this.rulesConf(() => base)
264283
val decoder = ruleDecoder(scalafixConfig)
284+
265285
val configuration = Configuration()
266-
.withConf(base)
286+
.withConf(targetConf)
267287
.withScalaVersion(scalaVersion)
268288
.withScalacOptions(scalacOptions)
269289
.withScalacClasspath(validatedClasspath.entries)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package scalafix.internal.v1
2+
3+
import metaconfig.Conf
4+
import metaconfig.Conf.Obj
5+
import metaconfig.ConfOps
6+
import metaconfig.internal.ConfGet
7+
8+
object ScalafixConfOps {
9+
def drop(original: Conf, key: String): Conf =
10+
ConfOps.fold(original)(obj = { confObj =>
11+
Obj(confObj.values.filterNot(_._1 == key))
12+
})
13+
14+
def overlay(original: Conf, key: String): Conf = {
15+
val child = ConfGet.getKey(original, key :: Nil)
16+
child.fold(original)(
17+
ConfOps.merge(drop(original, key), _)
18+
)
19+
}
20+
}

scalafix-interfaces/src/main/java/scalafix/interfaces/ScalafixArguments.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ ScalafixArguments withToolClasspath(
106106
ScalafixArguments withConfig(Optional<Path> config);
107107

108108
/**
109-
* @param mode The mode to run via --check or --stdout or --auto-suppress-linter-errors
109+
* @param mode The mode to run via --check or --stdout or --auto-suppress-linter-errors or --triggered
110110
*/
111111
ScalafixArguments withMode(ScalafixMainMode mode);
112112

scalafix-interfaces/src/main/java/scalafix/interfaces/ScalafixMainMode.java

+4
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,8 @@ public enum ScalafixMainMode {
2929
*/
3030
AUTO_SUPPRESS_LINTER_ERRORS,
3131

32+
/**
33+
* Use when the client triggers the run as a side effect of something else, as opposed to an explicit, interactive invocation. Write fixed contents in-place, with a custom configuration if it exists.
34+
*/
35+
IN_PLACE_TRIGGERED
3236
}

scalafix-tests/unit/src/test/scala/scalafix/tests/cli/CliSyntacticSuite.scala

+28
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,34 @@ class CliSyntacticSuite extends BaseCliSuite {
175175
expectedExit = ExitStatus.Ok
176176
)
177177

178+
check(
179+
name = "--triggered is respected",
180+
originalLayout = s"""|
181+
|/.scalafix.conf
182+
|rules = [
183+
| RemoveUnused
184+
|]
185+
|
186+
|triggered.rules = [ProcedureSyntax]
187+
|
188+
|/hello.scala
189+
|$original
190+
|""".stripMargin,
191+
args = Array("--triggered", "hello.scala"),
192+
expectedLayout = s"""|
193+
|/.scalafix.conf
194+
|rules = [
195+
| RemoveUnused
196+
|]
197+
|
198+
|triggered.rules = [ProcedureSyntax]
199+
|
200+
|/hello.scala
201+
|$expected
202+
|""".stripMargin,
203+
expectedExit = ExitStatus.Ok
204+
)
205+
178206
check(
179207
name = "linter error",
180208
originalLayout = s"""/foobar.scala
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package scalafix.tests.config
2+
3+
import metaconfig.Conf
4+
import metaconfig.internal.ConfGet
5+
import scalafix.internal.v1.Args
6+
import metaconfig.typesafeconfig.typesafeConfigMetaconfigParser
7+
import scalafix.internal.config.ScalafixConfig
8+
9+
class ArgsSuite extends munit.FunSuite {
10+
11+
private lazy val givenConf = Conf
12+
.parseString(
13+
"ArgsSuite",
14+
"""
15+
|rules = [DisableSyntax, RemoveUnused]
16+
|
17+
|triggered.rules = [DisableSyntax]
18+
|
19+
|DisableSyntax.noVars = true
20+
|DisableSyntax.noThrows = true
21+
|
22+
|triggered = {
23+
| DisableSyntax.noVars = false
24+
|}
25+
|
26+
|triggered.DisableSyntax.noReturns = true
27+
|""".stripMargin
28+
)
29+
.get
30+
31+
test("ignore triggered section if args.triggered is false") {
32+
val args = Args.default.copy(scalacOptions = "-Ywarn-unused" :: Nil)
33+
val config = ScalafixConfig()
34+
35+
assert(!args.triggered, "triggered should be false at default.")
36+
37+
val rulesConfigured = args.configuredRules(givenConf, config).get
38+
39+
assert(
40+
rulesConfigured.rules
41+
.map(_.name.value) == List("DisableSyntax", "RemoveUnused")
42+
)
43+
44+
val merged = args.maybeOverlaidConfWithTriggered(givenConf)
45+
46+
val disableSyntaxRule = ConfGet.getKey(merged, "DisableSyntax" :: Nil).get
47+
48+
val expected =
49+
Conf.Obj("noVars" -> Conf.Bool(true), "noThrows" -> Conf.Bool(true))
50+
51+
assertEquals(disableSyntaxRule, expected)
52+
}
53+
54+
test("use triggered section if args.triggered is true") {
55+
val args = Args.default.copy(triggered = true)
56+
val config = ScalafixConfig()
57+
58+
val rulesConfigured = args.configuredRules(givenConf, config).get
59+
60+
assert(rulesConfigured.rules.map(_.name.value) == List("DisableSyntax"))
61+
62+
val merged = args.maybeOverlaidConfWithTriggered(givenConf)
63+
64+
val disableSyntaxRule = ConfGet.getKey(merged, "DisableSyntax" :: Nil).get
65+
66+
val expected =
67+
Conf.Obj(
68+
"noVars" -> Conf.Bool(false),
69+
"noThrows" -> Conf.Bool(true),
70+
"noReturns" -> Conf.Bool(true)
71+
)
72+
73+
assertEquals(disableSyntaxRule, expected)
74+
}
75+
}

0 commit comments

Comments
 (0)