From 781eb684315319f278a74c84aa6f4cfab415bf84 Mon Sep 17 00:00:00 2001 From: Matthew de Detrich Date: Mon, 22 Aug 2022 13:18:50 +0200 Subject: [PATCH 01/11] Convert scalafmt integration to use a compile-only sourceset --- CHANGES.md | 1 + lib/build.gradle | 6 +- .../diffplug/spotless/scala/ScalaFmtStep.java | 93 ++----------------- .../glue/scalafmt/ScalafmtFormatterFunc.java | 56 +++++++++++ .../scalafmt/basic.cleanWithCustomConf_1.1.0 | 24 ----- .../scalafmt/basic.cleanWithCustomConf_2.0.1 | 25 ----- .../scala/scalafmt/basic.clean_1.1.0 | 16 ---- .../scala/scalafmt/basic.clean_2.0.1 | 18 ---- .../scala/scalafmt/basicPost2.0.0.clean | 18 ---- .../basicPost2.0.0.cleanWithCustomConf | 25 ----- .../resources/scala/scalafmt/scalafmt.conf | 2 + .../spotless/scala/ScalaFmtStepTest.java | 44 ++------- 12 files changed, 81 insertions(+), 247 deletions(-) create mode 100644 lib/src/scalafmt/java/com/diffplug/spotless/glue/scalafmt/ScalafmtFormatterFunc.java delete mode 100644 testlib/src/main/resources/scala/scalafmt/basic.cleanWithCustomConf_1.1.0 delete mode 100644 testlib/src/main/resources/scala/scalafmt/basic.cleanWithCustomConf_2.0.1 delete mode 100644 testlib/src/main/resources/scala/scalafmt/basic.clean_1.1.0 delete mode 100644 testlib/src/main/resources/scala/scalafmt/basic.clean_2.0.1 delete mode 100644 testlib/src/main/resources/scala/scalafmt/basicPost2.0.0.clean delete mode 100644 testlib/src/main/resources/scala/scalafmt/basicPost2.0.0.cleanWithCustomConf diff --git a/CHANGES.md b/CHANGES.md index 751749585f..446698d7ed 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,7 @@ This document is intended for Spotless developers. We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] +* Converted `scalafmt` integration to use a compile-only source set. (fixes [#524](https://github.com/diffplug/spotless/issues/524)) ## [2.28.1] - 2022-08-10 ### Fixed diff --git a/lib/build.gradle b/lib/build.gradle index e14e5c6438..0b3f4555b2 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -12,7 +12,8 @@ def NEEDS_GLUE = [ 'ktfmt', 'ktlint', 'flexmark', - 'diktat' + 'diktat', + 'scalafmt' ] for (glue in NEEDS_GLUE) { sourceSets.register(glue) { @@ -51,6 +52,9 @@ dependencies { ktlintCompileOnly "com.pinterest.ktlint:ktlint-ruleset-experimental:$VER_KTLINT" ktlintCompileOnly "com.pinterest.ktlint:ktlint-ruleset-standard:$VER_KTLINT" + String VER_SCALAFMT="3.5.9" + scalafmtCompileOnly "org.scalameta:scalafmt-core_2.13:$VER_SCALAFMT" + String VER_DIKTAT = "1.2.3" diktatCompileOnly "org.cqfn.diktat:diktat-rules:$VER_DIKTAT" diff --git a/lib/src/main/java/com/diffplug/spotless/scala/ScalaFmtStep.java b/lib/src/main/java/com/diffplug/spotless/scala/ScalaFmtStep.java index 8c8e4ccb2d..34c951cf06 100644 --- a/lib/src/main/java/com/diffplug/spotless/scala/ScalaFmtStep.java +++ b/lib/src/main/java/com/diffplug/spotless/scala/ScalaFmtStep.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 DiffPlug + * Copyright 2016-2022 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,13 +18,8 @@ import java.io.File; import java.io.IOException; import java.io.Serializable; -import java.lang.reflect.Method; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; +import java.lang.reflect.Constructor; import java.util.Collections; -import java.util.Objects; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import javax.annotation.Nullable; @@ -39,12 +34,8 @@ public class ScalaFmtStep { // prevent direct instantiation private ScalaFmtStep() {} - private static final Pattern VERSION_PRE_2_0 = Pattern.compile("[10]\\.(\\d+)\\.\\d+"); - private static final Pattern VERSION_PRE_3_0 = Pattern.compile("2\\.(\\d+)\\.\\d+"); - private static final String DEFAULT_VERSION = "3.0.8"; + private static final String DEFAULT_VERSION = "3.5.9"; static final String NAME = "scalafmt"; - static final String MAVEN_COORDINATE_PRE_2_0 = "com.geirsson:scalafmt-core_2.11:"; - static final String MAVEN_COORDINATE_PRE_3_0 = "org.scalameta:scalafmt-core_2.11:"; static final String MAVEN_COORDINATE = "org.scalameta:scalafmt-core_2.13:"; public static FormatterStep create(Provisioner provisioner) { @@ -52,10 +43,8 @@ public static FormatterStep create(Provisioner provisioner) { } public static FormatterStep create(String version, Provisioner provisioner, @Nullable File configFile) { - Objects.requireNonNull(version, "version"); - Objects.requireNonNull(provisioner, "provisioner"); return FormatterStep.createLazy(NAME, - () -> new State(version, provisioner, configFile), + () -> new State(JarState.from(MAVEN_COORDINATE + version, provisioner), configFile), State::createFormat); } @@ -69,78 +58,16 @@ static final class State implements Serializable { final JarState jarState; final FileSignature configSignature; - State(String version, Provisioner provisioner, @Nullable File configFile) throws IOException { - String mavenCoordinate; - Matcher versionMatcher; - if ((versionMatcher = VERSION_PRE_2_0.matcher(version)).matches()) { - mavenCoordinate = MAVEN_COORDINATE_PRE_2_0; - } else if ((versionMatcher = VERSION_PRE_3_0.matcher(version)).matches()) { - mavenCoordinate = MAVEN_COORDINATE_PRE_3_0; - } else { - mavenCoordinate = MAVEN_COORDINATE; - } - - this.jarState = JarState.from(mavenCoordinate + version, provisioner); + State(JarState jarState, @Nullable File configFile) throws IOException { + this.jarState = jarState; this.configSignature = FileSignature.signAsList(configFile == null ? Collections.emptySet() : Collections.singleton(configFile)); } FormatterFunc createFormat() throws Exception { - ClassLoader classLoader = jarState.getClassLoader(); - - // scalafmt returns instances of formatted, we get result by calling get() - Class formatted = classLoader.loadClass("org.scalafmt.Formatted"); - Method formattedGet = formatted.getMethod("get"); - - // this is how we actually do a format - Class scalafmt = classLoader.loadClass("org.scalafmt.Scalafmt"); - Class scalaSet = classLoader.loadClass("scala.collection.immutable.Set"); - - Object defaultScalaFmtConfig = scalafmt.getMethod("format$default$2").invoke(null); - Object emptyRange = scalafmt.getMethod("format$default$3").invoke(null); - Method formatMethod = scalafmt.getMethod("format", String.class, defaultScalaFmtConfig.getClass(), scalaSet); - - // now we just need to parse the config, if any - Object config; - if (configSignature.files().isEmpty()) { - config = defaultScalaFmtConfig; - } else { - File file = configSignature.getOnlyFile(); - - Class optionCls = classLoader.loadClass("scala.Option"); - Class configCls = classLoader.loadClass("org.scalafmt.config.Config"); - Class scalafmtCls = classLoader.loadClass("org.scalafmt.Scalafmt"); - - Object configured; - - try { - // scalafmt >= 1.6.0 - Method parseHoconConfig = scalafmtCls.getMethod("parseHoconConfig", String.class); - - String configStr = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8); - - configured = parseHoconConfig.invoke(null, configStr); - } catch (NoSuchMethodException e) { - // scalafmt >= v0.7.0-RC1 && scalafmt < 1.6.0 - Method fromHocon = configCls.getMethod("fromHoconString", String.class, optionCls); - Object fromHoconEmptyPath = configCls.getMethod("fromHoconString$default$2").invoke(null); - - String configStr = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8); - - configured = fromHocon.invoke(null, configStr, fromHoconEmptyPath); - } - - config = invokeNoArg(configured, "get"); - } - return input -> { - Object resultInsideFormatted = formatMethod.invoke(null, input, config, emptyRange); - return (String) formattedGet.invoke(resultInsideFormatted); - }; + final ClassLoader classLoader = jarState.getClassLoader(); + final Class formatterFunc = classLoader.loadClass("com.diffplug.spotless.glue.scalafmt.ScalafmtFormatterFunc"); + final Constructor constructor = formatterFunc.getConstructor(FileSignature.class); + return (FormatterFunc) constructor.newInstance(this.configSignature); } } - - private static Object invokeNoArg(Object obj, String toInvoke) throws Exception { - Class clazz = obj.getClass(); - Method method = clazz.getMethod(toInvoke); - return method.invoke(obj); - } } diff --git a/lib/src/scalafmt/java/com/diffplug/spotless/glue/scalafmt/ScalafmtFormatterFunc.java b/lib/src/scalafmt/java/com/diffplug/spotless/glue/scalafmt/ScalafmtFormatterFunc.java new file mode 100644 index 0000000000..b5924b2bac --- /dev/null +++ b/lib/src/scalafmt/java/com/diffplug/spotless/glue/scalafmt/ScalafmtFormatterFunc.java @@ -0,0 +1,56 @@ +/* + * Copyright 2022 DiffPlug + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.diffplug.spotless.glue.scalafmt; + +import java.io.File; +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; + +import org.scalafmt.Scalafmt; +import org.scalafmt.config.ScalafmtConfig; +import org.scalafmt.config.ScalafmtConfig$; + +import com.diffplug.spotless.FileSignature; +import com.diffplug.spotless.FormatterFunc; + +import scala.collection.immutable.Set$; + +public class ScalafmtFormatterFunc implements FormatterFunc { + private final FileSignature configSignature; + + public ScalafmtFormatterFunc(FileSignature configSignature) { + this.configSignature = configSignature; + } + + @Override + public String apply(String input) throws Exception { + ScalafmtConfig config; + if (configSignature.files().isEmpty()) { + // Note that reflection is used here only because Scalafmt has a method called + // default which happens to be a reserved Java keyword. The only way to call + // such methods is by reflection, see + // https://vlkan.com/blog/post/2015/11/20/scala-method-with-java-reserved-keyword/ + Method method = ScalafmtConfig$.MODULE$.getClass().getDeclaredMethod("default"); + config = (ScalafmtConfig) method.invoke(ScalafmtConfig$.MODULE$); + } else { + File file = configSignature.getOnlyFile(); + String configStr = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8); + config = Scalafmt.parseHoconConfig(configStr).get(); + } + return Scalafmt.format(input, config, Set$.MODULE$.empty()).get(); + } +} diff --git a/testlib/src/main/resources/scala/scalafmt/basic.cleanWithCustomConf_1.1.0 b/testlib/src/main/resources/scala/scalafmt/basic.cleanWithCustomConf_1.1.0 deleted file mode 100644 index 98bf69b7af..0000000000 --- a/testlib/src/main/resources/scala/scalafmt/basic.cleanWithCustomConf_1.1.0 +++ /dev/null @@ -1,24 +0,0 @@ -@foobar("annot", { - val x = 2 - val y = 2 // y=2 - x + y -}) -object a - extends b - with c { - def foo[ - T: Int#Double#Triple, - R <% String]( - @annot1 - x: Int @annot2 = - 2, - y: Int = 3) - : Int = { - "match" match { - case 1 | 2 => - 3 - case 2 => - 2 - } - } -} diff --git a/testlib/src/main/resources/scala/scalafmt/basic.cleanWithCustomConf_2.0.1 b/testlib/src/main/resources/scala/scalafmt/basic.cleanWithCustomConf_2.0.1 deleted file mode 100644 index fc8267fb75..0000000000 --- a/testlib/src/main/resources/scala/scalafmt/basic.cleanWithCustomConf_2.0.1 +++ /dev/null @@ -1,25 +0,0 @@ -@foobar("annot", { - val x = 2 - val y = 2 // y=2 - x + y -}) -object a - extends b - with c { - def foo[ - T: Int#Double#Triple, - R <% String - ]( - @annot1 - x: Int @annot2 = - 2, - y: Int = 3 - ): Int = { - "match" match { - case 1 | 2 => - 3 - case 2 => - 2 - } - } -} diff --git a/testlib/src/main/resources/scala/scalafmt/basic.clean_1.1.0 b/testlib/src/main/resources/scala/scalafmt/basic.clean_1.1.0 deleted file mode 100644 index 922a2ccbb9..0000000000 --- a/testlib/src/main/resources/scala/scalafmt/basic.clean_1.1.0 +++ /dev/null @@ -1,16 +0,0 @@ -@foobar("annot", { - val x = 2 - val y = 2 // y=2 - x + y -}) -object a extends b with c { - def foo[T: Int#Double#Triple, R <% String](@annot1 - x: Int @annot2 = 2, - y: Int = 3): Int = { - "match" match { - case 1 | 2 => - 3 - case 2 => 2 - } - } -} diff --git a/testlib/src/main/resources/scala/scalafmt/basic.clean_2.0.1 b/testlib/src/main/resources/scala/scalafmt/basic.clean_2.0.1 deleted file mode 100644 index b838dfea65..0000000000 --- a/testlib/src/main/resources/scala/scalafmt/basic.clean_2.0.1 +++ /dev/null @@ -1,18 +0,0 @@ -@foobar("annot", { - val x = 2 - val y = 2 // y=2 - x + y -}) -object a extends b with c { - def foo[T: Int#Double#Triple, R <% String]( - @annot1 - x: Int @annot2 = 2, - y: Int = 3 - ): Int = { - "match" match { - case 1 | 2 => - 3 - case 2 => 2 - } - } -} diff --git a/testlib/src/main/resources/scala/scalafmt/basicPost2.0.0.clean b/testlib/src/main/resources/scala/scalafmt/basicPost2.0.0.clean deleted file mode 100644 index b838dfea65..0000000000 --- a/testlib/src/main/resources/scala/scalafmt/basicPost2.0.0.clean +++ /dev/null @@ -1,18 +0,0 @@ -@foobar("annot", { - val x = 2 - val y = 2 // y=2 - x + y -}) -object a extends b with c { - def foo[T: Int#Double#Triple, R <% String]( - @annot1 - x: Int @annot2 = 2, - y: Int = 3 - ): Int = { - "match" match { - case 1 | 2 => - 3 - case 2 => 2 - } - } -} diff --git a/testlib/src/main/resources/scala/scalafmt/basicPost2.0.0.cleanWithCustomConf b/testlib/src/main/resources/scala/scalafmt/basicPost2.0.0.cleanWithCustomConf deleted file mode 100644 index fc8267fb75..0000000000 --- a/testlib/src/main/resources/scala/scalafmt/basicPost2.0.0.cleanWithCustomConf +++ /dev/null @@ -1,25 +0,0 @@ -@foobar("annot", { - val x = 2 - val y = 2 // y=2 - x + y -}) -object a - extends b - with c { - def foo[ - T: Int#Double#Triple, - R <% String - ]( - @annot1 - x: Int @annot2 = - 2, - y: Int = 3 - ): Int = { - "match" match { - case 1 | 2 => - 3 - case 2 => - 2 - } - } -} diff --git a/testlib/src/main/resources/scala/scalafmt/scalafmt.conf b/testlib/src/main/resources/scala/scalafmt/scalafmt.conf index 5007f5e8ff..bcfec161f4 100644 --- a/testlib/src/main/resources/scala/scalafmt/scalafmt.conf +++ b/testlib/src/main/resources/scala/scalafmt/scalafmt.conf @@ -1,2 +1,4 @@ +version = 3.5.9 +runner.dialect = scala213 style = defaultWithAlign # For pretty alignment. maxColumn = 20 # For my teensy narrow display diff --git a/testlib/src/test/java/com/diffplug/spotless/scala/ScalaFmtStepTest.java b/testlib/src/test/java/com/diffplug/spotless/scala/ScalaFmtStepTest.java index 0f42252d36..8003607962 100644 --- a/testlib/src/test/java/com/diffplug/spotless/scala/ScalaFmtStepTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/scala/ScalaFmtStepTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 DiffPlug + * Copyright 2016-2022 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ import java.io.File; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; +import java.util.NoSuchElementException; import org.junit.jupiter.api.Test; @@ -34,38 +34,16 @@ class ScalaFmtStepTest extends ResourceHarness { @Test void behaviorDefaultConfig() throws Exception { - StepHarness.forStep(ScalaFmtStep.create("1.1.0", TestProvisioner.mavenCentral(), null)) - .testResource("scala/scalafmt/basic.dirty", "scala/scalafmt/basic.clean_1.1.0"); - StepHarness.forStep(ScalaFmtStep.create("2.0.1", TestProvisioner.mavenCentral(), null)) - .testResource("scala/scalafmt/basic.dirty", "scala/scalafmt/basic.clean_2.0.1"); StepHarness.forStep(ScalaFmtStep.create("3.0.0", TestProvisioner.mavenCentral(), null)) .testResource("scala/scalafmt/basic.dirty", "scala/scalafmt/basic.clean_3.0.0"); } @Test void behaviorCustomConfig() throws Exception { - StepHarness.forStep(ScalaFmtStep.create("1.1.0", TestProvisioner.mavenCentral(), createTestFile("scala/scalafmt/scalafmt.conf"))) - .testResource("scala/scalafmt/basic.dirty", "scala/scalafmt/basic.cleanWithCustomConf_1.1.0"); - StepHarness.forStep(ScalaFmtStep.create("2.0.1", TestProvisioner.mavenCentral(), createTestFile("scala/scalafmt/scalafmt.conf"))) - .testResource("scala/scalafmt/basic.dirty", "scala/scalafmt/basic.cleanWithCustomConf_2.0.1"); StepHarness.forStep(ScalaFmtStep.create("3.0.0", TestProvisioner.mavenCentral(), createTestFile("scala/scalafmt/scalafmt.conf"))) .testResource("scala/scalafmt/basic.dirty", "scala/scalafmt/basic.cleanWithCustomConf_3.0.0"); } - @Test - void behaviorDefaultConfigVersion_2_0_0() throws Exception { - FormatterStep step = ScalaFmtStep.create("2.0.0", TestProvisioner.mavenCentral(), null); - StepHarness.forStep(step) - .testResource("scala/scalafmt/basic.dirty", "scala/scalafmt/basicPost2.0.0.clean"); - } - - @Test - void behaviorCustomConfigVersion_2_0_0() throws Exception { - FormatterStep step = ScalaFmtStep.create("2.0.0", TestProvisioner.mavenCentral(), createTestFile("scala/scalafmt/scalafmt.conf")); - StepHarness.forStep(step) - .testResource("scala/scalafmt/basic.dirty", "scala/scalafmt/basicPost2.0.0.cleanWithCustomConf"); - } - @Test void behaviorDefaultConfigVersion_3_0_0() throws Exception { FormatterStep step = ScalaFmtStep.create("3.0.0", TestProvisioner.mavenCentral(), null); @@ -83,7 +61,7 @@ void behaviorCustomConfigVersion_3_0_0() throws Exception { @Test void equality() throws Exception { new SerializableEqualityTester() { - String version = "0.5.1"; + String version = "3.5.9"; File configFile = null; @Override @@ -91,7 +69,7 @@ protected void setupTest(API api) throws IOException { // same version == same api.areDifferentThan(); // change the version, and it's different - version = "0.5.0"; + version = "3.5.8"; api.areDifferentThan(); // add a config file, and its different configFile = createTestFile("scala/scalafmt/scalafmt.conf"); @@ -113,18 +91,10 @@ void invalidConfiguration() throws Exception { File invalidConfFile = createTestFile("scala/scalafmt/scalafmt.invalid.conf"); Provisioner provisioner = TestProvisioner.mavenCentral(); - InvocationTargetException exception; - - exception = assertThrows(InvocationTargetException.class, - () -> StepHarness.forStep(ScalaFmtStep.create("1.1.0", provisioner, invalidConfFile)).test("", "")); - assertThat(exception.getTargetException().getMessage()).contains("Invalid fields: invalidScalaFmtConfigField"); - - exception = assertThrows(InvocationTargetException.class, - () -> StepHarness.forStep(ScalaFmtStep.create("2.0.1", provisioner, invalidConfFile)).test("", "")); - assertThat(exception.getTargetException().getMessage()).contains("Invalid field: invalidScalaFmtConfigField"); + NoSuchElementException exception; - exception = assertThrows(InvocationTargetException.class, + exception = assertThrows(NoSuchElementException.class, () -> StepHarness.forStep(ScalaFmtStep.create("3.0.0", provisioner, invalidConfFile)).test("", "")); - assertThat(exception.getTargetException().getMessage()).contains("found option 'invalidScalaFmtConfigField' which wasn't expected"); + assertThat(exception.getMessage()).contains("found option 'invalidScalaFmtConfigField' which wasn't expected"); } } From 137392f5fe38deaddebce6114d7e06ea8b517396 Mon Sep 17 00:00:00 2001 From: Matthew de Detrich Date: Tue, 23 Aug 2022 01:06:12 +0200 Subject: [PATCH 02/11] Allow configuration of scalaMajorVersion --- .../diffplug/spotless/scala/ScalaFmtStep.java | 18 +++++++++++++++--- .../gradle/spotless/ScalaExtension.java | 14 +++++++++++--- .../spotless/maven/scala/Scalafmt.java | 6 +++++- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/scala/ScalaFmtStep.java b/lib/src/main/java/com/diffplug/spotless/scala/ScalaFmtStep.java index 34c951cf06..6ef9fcd5a7 100644 --- a/lib/src/main/java/com/diffplug/spotless/scala/ScalaFmtStep.java +++ b/lib/src/main/java/com/diffplug/spotless/scala/ScalaFmtStep.java @@ -35,16 +35,24 @@ public class ScalaFmtStep { private ScalaFmtStep() {} private static final String DEFAULT_VERSION = "3.5.9"; + + private static final String DEFAULT_SCALA_MAJOR_VERSION = "2.13"; static final String NAME = "scalafmt"; - static final String MAVEN_COORDINATE = "org.scalameta:scalafmt-core_2.13:"; + static final String MAVEN_COORDINATE = "org.scalameta:scalafmt-core_"; public static FormatterStep create(Provisioner provisioner) { - return create(defaultVersion(), provisioner, null); + return create(defaultVersion(), defaultScalaMajorVersion(), provisioner, null); } public static FormatterStep create(String version, Provisioner provisioner, @Nullable File configFile) { + return create(version, defaultScalaMajorVersion(), provisioner, configFile); + } + + public static FormatterStep create(String version, @Nullable String scalaMajorVersion, Provisioner provisioner, @Nullable File configFile) { + String finalScalaMajorVersion = scalaMajorVersion == null ? DEFAULT_SCALA_MAJOR_VERSION : scalaMajorVersion; + return FormatterStep.createLazy(NAME, - () -> new State(JarState.from(MAVEN_COORDINATE + version, provisioner), configFile), + () -> new State(JarState.from(MAVEN_COORDINATE + finalScalaMajorVersion + ":" + version, provisioner), configFile), State::createFormat); } @@ -52,6 +60,10 @@ public static String defaultVersion() { return DEFAULT_VERSION; } + public static String defaultScalaMajorVersion() { + return DEFAULT_SCALA_MAJOR_VERSION; + } + static final class State implements Serializable { private static final long serialVersionUID = 1L; diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java index f6db64348d..06fddc38e3 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java @@ -48,21 +48,29 @@ public ScalaFmtConfig scalafmt(String version) { public class ScalaFmtConfig { final String version; @Nullable + String scalaMajorVersion; + @Nullable Object configFile; ScalaFmtConfig(String version) { this.version = Objects.requireNonNull(version); - addStep(createStep()); } - public void configFile(Object configFile) { + public ScalaFmtConfig configFile(Object configFile) { this.configFile = Objects.requireNonNull(configFile); replaceStep(createStep()); + return this; + } + + public ScalaFmtConfig scalaMajorVersion(String scalaMajorVersion) { + this.scalaMajorVersion = Objects.requireNonNull(scalaMajorVersion); + replaceStep(createStep()); + return this; } private FormatterStep createStep() { File resolvedConfigFile = configFile == null ? null : getProject().file(configFile); - return ScalaFmtStep.create(version, provisioner(), resolvedConfigFile); + return ScalaFmtStep.create(version, scalaMajorVersion, provisioner(), resolvedConfigFile); } } diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/scala/Scalafmt.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/scala/Scalafmt.java index 470a5ddb72..0de90c4a7f 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/scala/Scalafmt.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/scala/Scalafmt.java @@ -32,10 +32,14 @@ public class Scalafmt implements FormatterStepFactory { @Parameter private String version; + @Parameter + private String scalaMajorVersion; + @Override public FormatterStep newFormatterStep(FormatterStepConfig config) { String scalafmtVersion = version != null ? version : ScalaFmtStep.defaultVersion(); + String scalafmtScalaMajorVersion = scalaMajorVersion != null ? scalaMajorVersion : ScalaFmtStep.defaultScalaMajorVersion(); File configFile = config.getFileLocator().locateFile(file); - return ScalaFmtStep.create(scalafmtVersion, config.getProvisioner(), configFile); + return ScalaFmtStep.create(scalafmtVersion, scalafmtScalaMajorVersion, config.getProvisioner(), configFile); } } From abe0be95ee0a819fa165464405d2da4038e48d10 Mon Sep 17 00:00:00 2001 From: Matthew de Detrich Date: Tue, 23 Aug 2022 01:16:40 +0200 Subject: [PATCH 03/11] Resolve formatting issues --- .../main/java/com/diffplug/gradle/spotless/ScalaExtension.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java index 06fddc38e3..841c35e6d6 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2020 DiffPlug + * Copyright 2016-2022 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From df59712817490eb87451770b8a32f461160622ea Mon Sep 17 00:00:00 2001 From: Matthew de Detrich Date: Tue, 23 Aug 2022 01:20:35 +0200 Subject: [PATCH 04/11] More formatting issues --- .../main/java/com/diffplug/spotless/maven/scala/Scalafmt.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/scala/Scalafmt.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/scala/Scalafmt.java index 0de90c4a7f..e0dc44bef5 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/scala/Scalafmt.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/scala/Scalafmt.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 DiffPlug + * Copyright 2016-2022 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 677415e9c197e81a46d1f1f7d8d7d00b13840007 Mon Sep 17 00:00:00 2001 From: Matthew de Detrich Date: Tue, 23 Aug 2022 01:38:57 +0200 Subject: [PATCH 05/11] Fix accidental removal of addStep --- .../main/java/com/diffplug/gradle/spotless/ScalaExtension.java | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java index 841c35e6d6..8a8765b539 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/ScalaExtension.java @@ -54,6 +54,7 @@ public class ScalaFmtConfig { ScalaFmtConfig(String version) { this.version = Objects.requireNonNull(version); + addStep(createStep()); } public ScalaFmtConfig configFile(Object configFile) { From 30d72d82f9183274bfcffced5fc7f4525ed80946 Mon Sep 17 00:00:00 2001 From: Matthew de Detrich Date: Tue, 23 Aug 2022 11:40:06 +0200 Subject: [PATCH 06/11] Add documentation for majorScalaVersion --- CHANGES.md | 1 + plugin-gradle/README.md | 4 ++-- plugin-maven/README.md | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 46524605ac..185ca636ee 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,6 +12,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Changes * Converted `scalafmt` integration to use a compile-only source set. (fixes [#524](https://github.com/diffplug/spotless/issues/524)) +* `scalafmt` integration now has a configuration option `majorScalaVersion` that allows you to configure the Scala version that gets resolved from the maven artifact. [#1283](https://github.com/diffplug/spotless/pull/1283) * Add the `ktlint` rule in error messages when `ktlint` fails to apply a fix ([#1279](https://github.com/diffplug/spotless/pull/1279)) ## [2.28.1] - 2022-08-10 diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index 53e77a9ced..d107dc7f98 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -388,8 +388,8 @@ spotless { ```gradle spotless { scala { - // version and configFile are both optional - scalafmt('2.6.1').configFile('scalafmt.conf') + // version and configFile, majorScalaVersion are all optional + scalafmt('2.6.1').configFile('scalafmt.conf').majorScalaVersion('2.13') ``` diff --git a/plugin-maven/README.md b/plugin-maven/README.md index fa4cf55c74..0b75c59434 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -395,6 +395,7 @@ Groovy-Eclipse formatting errors/warnings lead per default to a build failure. T 2.0.1 ${project.basedir}/scalafmt.conf + 2.13 ``` From 872424a816b8f1068dfa3b7ae82c447ac342baba Mon Sep 17 00:00:00 2001 From: Matthew de Detrich Date: Tue, 23 Aug 2022 11:40:59 +0200 Subject: [PATCH 07/11] Update scalafmt versions in documentation --- plugin-gradle/README.md | 2 +- plugin-maven/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index d107dc7f98..7e0a39ab0e 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -389,7 +389,7 @@ spotless { spotless { scala { // version and configFile, majorScalaVersion are all optional - scalafmt('2.6.1').configFile('scalafmt.conf').majorScalaVersion('2.13') + scalafmt('3.5.9').configFile('scalafmt.conf').majorScalaVersion('2.13') ``` diff --git a/plugin-maven/README.md b/plugin-maven/README.md index 0b75c59434..f29d34f5bd 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -393,7 +393,7 @@ Groovy-Eclipse formatting errors/warnings lead per default to a build failure. T ```xml - 2.0.1 + 3.5.9 ${project.basedir}/scalafmt.conf 2.13 From 24ca9ec83ed01917bb13827c2f2a26a421610f82 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Tue, 23 Aug 2022 12:32:51 -0700 Subject: [PATCH 08/11] Add info about changes to scalafmt default version. --- CHANGES.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 185ca636ee..0fc7f14021 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,10 +10,12 @@ This document is intended for Spotless developers. We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] +### Added +* `scalafmt` integration now has a configuration option `majorScalaVersion` that allows you to configure the Scala version that gets resolved from the maven artifact ([#1283](https://github.com/diffplug/spotless/pull/1283)) + * Converted `scalafmt` integration to use a compile-only source set (fixes [#524](https://github.com/diffplug/spotless/issues/524)) ### Changes -* Converted `scalafmt` integration to use a compile-only source set. (fixes [#524](https://github.com/diffplug/spotless/issues/524)) -* `scalafmt` integration now has a configuration option `majorScalaVersion` that allows you to configure the Scala version that gets resolved from the maven artifact. [#1283](https://github.com/diffplug/spotless/pull/1283) * Add the `ktlint` rule in error messages when `ktlint` fails to apply a fix ([#1279](https://github.com/diffplug/spotless/pull/1279)) +* Bump default `scalafmt` to latest `3.0.8` -> `3.5.9` (removed support for pre-`3.0.0`) ([#1283](https://github.com/diffplug/spotless/pull/1283)) ## [2.28.1] - 2022-08-10 ### Fixed From 735c7b5228a46a5d292b0aecfdc2d459932ac414 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Tue, 23 Aug 2022 12:33:02 -0700 Subject: [PATCH 09/11] Update the tool-specific changelogs. --- plugin-gradle/CHANGES.md | 3 +++ plugin-maven/CHANGES.md | 3 +++ 2 files changed, 6 insertions(+) diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 72d600688c..30235660d5 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -3,8 +3,11 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `3.27.0`). ## [Unreleased] +### Added +* `scalafmt` integration now has a configuration option `majorScalaVersion` that allows you to configure the Scala version that gets resolved from the maven artifact ([#1283](https://github.com/diffplug/spotless/pull/1283)) ### Changes * Add the `ktlint` rule in error messages when `ktlint` fails to apply a fix ([#1279](https://github.com/diffplug/spotless/pull/1279)) +* Bump default `scalafmt` to latest `3.0.8` -> `3.5.9` (removed support for pre-`3.0.0`) ([#1283](https://github.com/diffplug/spotless/pull/1283)) ## [6.9.1] - 2022-08-10 ### Fixed diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 7366c3b731..ced0a0baba 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -3,8 +3,11 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] +### Added +* `scalafmt` integration now has a configuration option `majorScalaVersion` that allows you to configure the Scala version that gets resolved from the maven artifact ([#1283](https://github.com/diffplug/spotless/pull/1283)) ### Changes * Add the `ktlint` rule in error messages when `ktlint` fails to apply a fix ([#1279](https://github.com/diffplug/spotless/pull/1279)) +* Bump default `scalafmt` to latest `3.0.8` -> `3.5.9` (removed support for pre-`3.0.0`) ([#1283](https://github.com/diffplug/spotless/pull/1283)) ## [2.24.1] - 2022-08-10 ### Fixed From a75877c085b283a8eafb9397008cb7d6ce208217 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Tue, 23 Aug 2022 12:37:36 -0700 Subject: [PATCH 10/11] Massive speedup. FormatterFunc is instantiated lazily and is not involved in serialization/equality, so good to eagerly initialize in the constructor. --- .../glue/scalafmt/ScalafmtFormatterFunc.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/src/scalafmt/java/com/diffplug/spotless/glue/scalafmt/ScalafmtFormatterFunc.java b/lib/src/scalafmt/java/com/diffplug/spotless/glue/scalafmt/ScalafmtFormatterFunc.java index b5924b2bac..49e1b6a1be 100644 --- a/lib/src/scalafmt/java/com/diffplug/spotless/glue/scalafmt/ScalafmtFormatterFunc.java +++ b/lib/src/scalafmt/java/com/diffplug/spotless/glue/scalafmt/ScalafmtFormatterFunc.java @@ -30,15 +30,9 @@ import scala.collection.immutable.Set$; public class ScalafmtFormatterFunc implements FormatterFunc { - private final FileSignature configSignature; + private final ScalafmtConfig config; - public ScalafmtFormatterFunc(FileSignature configSignature) { - this.configSignature = configSignature; - } - - @Override - public String apply(String input) throws Exception { - ScalafmtConfig config; + public ScalafmtFormatterFunc(FileSignature configSignature) throws Exception { if (configSignature.files().isEmpty()) { // Note that reflection is used here only because Scalafmt has a method called // default which happens to be a reserved Java keyword. The only way to call @@ -51,6 +45,10 @@ public String apply(String input) throws Exception { String configStr = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8); config = Scalafmt.parseHoconConfig(configStr).get(); } + } + + @Override + public String apply(String input) { return Scalafmt.format(input, config, Set$.MODULE$.empty()).get(); } } From e9d31502b710b56b57bbcc46be02f11313dfbfe0 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Tue, 23 Aug 2022 13:02:51 -0700 Subject: [PATCH 11/11] Fix test. --- .../com/diffplug/spotless/scala/ScalaFmtStepTest.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/testlib/src/test/java/com/diffplug/spotless/scala/ScalaFmtStepTest.java b/testlib/src/test/java/com/diffplug/spotless/scala/ScalaFmtStepTest.java index 8003607962..bad573e985 100644 --- a/testlib/src/test/java/com/diffplug/spotless/scala/ScalaFmtStepTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/scala/ScalaFmtStepTest.java @@ -20,7 +20,7 @@ import java.io.File; import java.io.IOException; -import java.util.NoSuchElementException; +import java.lang.reflect.InvocationTargetException; import org.junit.jupiter.api.Test; @@ -91,10 +91,8 @@ void invalidConfiguration() throws Exception { File invalidConfFile = createTestFile("scala/scalafmt/scalafmt.invalid.conf"); Provisioner provisioner = TestProvisioner.mavenCentral(); - NoSuchElementException exception; - - exception = assertThrows(NoSuchElementException.class, + InvocationTargetException exception = assertThrows(InvocationTargetException.class, () -> StepHarness.forStep(ScalaFmtStep.create("3.0.0", provisioner, invalidConfFile)).test("", "")); - assertThat(exception.getMessage()).contains("found option 'invalidScalaFmtConfigField' which wasn't expected"); + assertThat(exception.getCause().getMessage()).contains("found option 'invalidScalaFmtConfigField' which wasn't expected"); } }