Skip to content
Open
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
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (

## [Unreleased]
### Added
- `scalafmt()` now reads the version from the `version` field in the scalafmt config file when no version is explicitly set in the plugin config, falling back to the built-in default only if neither is available. ([#2922](https://github.com/diffplug/spotless/pull/2922))
- Add `javaparserVersion` option to the Cleanthat step, allowing callers to override the JavaParser version pulled in transitively by Cleanthat. ([#2903](https://github.com/diffplug/spotless/pull/2903))
### Fixed
- Fix non-idempotent formatting when `importOrder()` is combined with `greclipse()`: a single catch-all group no longer strips blank lines that `greclipse()` independently inserted between import groups. ([#2914](https://github.com/diffplug/spotless/pull/2914))
Expand Down
27 changes: 23 additions & 4 deletions lib/src/main/java/com/diffplug/spotless/scala/ScalaFmtStep.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 DiffPlug
* Copyright 2016-2026 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -20,7 +20,9 @@
import java.io.Serial;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.nio.file.Files;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;

import javax.annotation.Nullable;
Expand Down Expand Up @@ -54,15 +56,16 @@ public static FormatterStep create(Provisioner provisioner) {
return create(defaultVersion(), defaultScalaMajorVersion(), provisioner, null);
}

public static FormatterStep create(String version, Provisioner provisioner, @Nullable File configFile) {
public static FormatterStep create(@Nullable 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) {
public static FormatterStep create(@Nullable String version, @Nullable String scalaMajorVersion, Provisioner provisioner, @Nullable File configFile) {
String finalVersion = version != null ? version : versionFromConfig(configFile).orElse(defaultVersion());
String finalScalaMajorVersion = scalaMajorVersion == null ? DEFAULT_SCALA_MAJOR_VERSION : scalaMajorVersion;

return FormatterStep.create(NAME,
new ScalaFmtStep(JarState.promise(() -> JarState.from(MAVEN_COORDINATE + finalScalaMajorVersion + ":" + version, provisioner)), configFile),
new ScalaFmtStep(JarState.promise(() -> JarState.from(MAVEN_COORDINATE + finalScalaMajorVersion + ":" + finalVersion, provisioner)), configFile),
ScalaFmtStep::equalityState,
State::createFormat);
}
Expand All @@ -75,6 +78,22 @@ public static String defaultScalaMajorVersion() {
return DEFAULT_SCALA_MAJOR_VERSION;
}

private static Optional<String> versionFromConfig(@Nullable File configFile) {
try {
return configFile == null || !configFile.exists() ? Optional.empty()
: Files.readAllLines(configFile.toPath())
.stream()
.filter(line -> line.trim().startsWith("version"))
.findFirst()
.flatMap(line -> {
var parts = line.replaceAll("\\s", "").split("=");
return parts.length < 2 ? Optional.empty() : Optional.of(parts[1]);
});
} catch (IOException e) {
return Optional.empty();
}
}

private State equalityState() throws IOException {
return new State(jarState.get(), configFile);
}
Expand Down
1 change: 1 addition & 0 deletions plugin-gradle/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (

## [Unreleased]
### Added
- `scalafmt()` now reads the version from the `version` field in the scalafmt config file when no version is explicitly set in the plugin config, falling back to the built-in default only if neither is available. ([#2922](https://github.com/diffplug/spotless/pull/2922))
- Add `withIndentStyle` and `withIndentSize` configuration to `tableTestFormatter` for setting the fallback indent when no `.editorconfig` is found. ([#2893](https://github.com/diffplug/spotless/pull/2893))
- Add `javaparserVersion(...)` to `cleanthat`, allowing users to override the JavaParser version pulled in transitively by Cleanthat. ([#2903](https://github.com/diffplug/spotless/pull/2903))
### Fixed
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 DiffPlug
* Copyright 2016-2026 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -35,22 +35,20 @@ public ScalaExtension(SpotlessExtension spotless) {
}

public ScalaFmtConfig scalafmt() {
return scalafmt(ScalaFmtStep.defaultVersion());
return new ScalaFmtConfig(null);
}

public ScalaFmtConfig scalafmt(String version) {
return new ScalaFmtConfig(version);
return new ScalaFmtConfig(Objects.requireNonNull(version));
}

public class ScalaFmtConfig {
final String version;
@Nullable
String scalaMajorVersion;
@Nullable
Object configFile;
@Nullable final String version;
@Nullable String scalaMajorVersion;
@Nullable Object configFile;

ScalaFmtConfig(String version) {
this.version = Objects.requireNonNull(version);
ScalaFmtConfig(@Nullable String version) {
this.version = version;
addStep(createStep());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 DiffPlug
* Copyright 2016-2026 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -20,6 +20,25 @@
import org.junit.jupiter.api.Test;

class ScalaExtensionTest extends GradleIntegrationHarness {
@Test
void versionFromConfig() throws IOException {
setFile("build.gradle").toLines(
"plugins {",
" id 'com.diffplug.spotless'",
"}",
"repositories { mavenCentral() }",
"apply plugin: 'scala'",
"spotless {",
" scala {",
" scalafmt().configFile('scalafmt.conf')",
" }",
"}");
setFile("scalafmt.conf").toResource("scala/scalafmt/scalafmt_newer.conf");
setFile("src/main/scala/basic.scala").toResource("scala/scalafmt/basic.dirty");
gradleRunner().withArguments("spotlessApply").build();
assertFile("src/main/scala/basic.scala").sameAsResource("scala/scalafmt/basic.cleanWithCustomConf_3.0.0");
}

@Test
void integration() throws IOException {
setFile("build.gradle").toLines(
Expand Down
1 change: 1 addition & 0 deletions plugin-maven/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (

## [Unreleased]
### Added
- `<scalafmt>` now reads the version from the `version` field in the scalafmt config file when no `<version>` is explicitly set, falling back to the built-in default only if neither is available. ([#2922](https://github.com/diffplug/spotless/pull/2922))
- Add `<javaparserVersion>` option to `<cleanthat>`, allowing users to override the JavaParser version pulled in transitively by Cleanthat. ([#2903](https://github.com/diffplug/spotless/pull/2903))
### Fixed
- Fix non-idempotent formatting when `importOrder()` is combined with `greclipse()`: a single catch-all group no longer strips blank lines that `greclipse()` independently inserted between import groups. ([#2914](https://github.com/diffplug/spotless/pull/2914))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2022 DiffPlug
* Copyright 2016-2026 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -37,9 +37,7 @@ public class Scalafmt implements FormatterStepFactory {

@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, scalafmtScalaMajorVersion, config.getProvisioner(), configFile);
return ScalaFmtStep.create(version, scalaMajorVersion, config.getProvisioner(), configFile);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 DiffPlug
* Copyright 2016-2026 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -39,6 +39,18 @@ void testScalafmtWithCustomConfig() throws Exception {
runTest("scala/scalafmt/basic.cleanWithCustomConf_3.0.0");
}

@Test
void testScalafmtVersionFromConfig() throws Exception {
setFile("scalafmt.conf").toResource("scala/scalafmt/scalafmt_newer.conf");

writePomWithScalaSteps(
"<scalafmt>",
" <file>${project.basedir}/scalafmt.conf</file>",
"</scalafmt>");

runTest("scala/scalafmt/basic.cleanWithCustomConf_3.0.0");
}

private void runTest(String s) throws Exception {
String path = "src/main/scala/test.scala";
setFile(path).toResource("scala/scalafmt/basic.dirty");
Expand Down
5 changes: 5 additions & 0 deletions testlib/src/main/resources/scala/scalafmt/scalafmt_newer.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
version = 3.11.0
runner.dialect = scala213
runner.dialectFeatures = [relaxedLambdaSyntax]
style = defaultWithAlign
maxColumn = 20
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 DiffPlug
* Copyright 2016-2026 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -88,6 +88,24 @@ protected FormatterStep create() {
}.testEquals();
}

@Test
void behaviorVersionFromConfigFile() {
StepHarness.forStep(ScalaFmtStep.create((String) null, TestProvisioner.mavenCentral(), createTestFile("scala/scalafmt/scalafmt.conf")))
.testResource("scala/scalafmt/basic.dirty", "scala/scalafmt/basic.cleanWithCustomConf_3.0.0");
}

@Test
void behaviorVersionFromConfigFileNewerVersion() {
StepHarness.forStep(ScalaFmtStep.create((String) null, TestProvisioner.mavenCentral(), createTestFile("scala/scalafmt/scalafmt_newer.conf")))
.testResource("scala/scalafmt/basic.dirty", "scala/scalafmt/basic.cleanWithCustomConf_3.0.0");
}

@Test
void behaviorDefaultVersionWithoutConfigFile() {
StepHarness.forStep(ScalaFmtStep.create((String) null, TestProvisioner.mavenCentral(), null))
.testResource("scala/scalafmt/basic.dirty", "scala/scalafmt/basic.clean_3.0.0");
}

@Test
void invalidConfiguration() {
File invalidConfFile = createTestFile("scala/scalafmt/scalafmt.invalid.conf");
Expand Down
Loading