Skip to content

Commit 3fa38e5

Browse files
authored
Merge branch 'main' into fix/buf-on-windows
2 parents bd113c2 + fe1c64a commit 3fa38e5

File tree

11 files changed

+111
-81
lines changed

11 files changed

+111
-81
lines changed

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
1414
* `FileSignature.Promised` and `JarState.Promised` to facilitate round-trip serialization for the Gradle configuration cache. ([#1945](https://github.com/diffplug/spotless/pull/1945))
1515
* Respect `.editorconfig` settings for formatting shell via `shfmt` ([#2031](https://github.com/diffplug/spotless/pull/2031))
1616
### Fixed
17+
* Check if ktlint_code_style is set in .editorconfig before overriding it ([#2143](https://github.com/diffplug/spotless/issues/2143))
1718
* Ignore system git config when running tests ([#1990](https://github.com/diffplug/spotless/issues/1990))
1819
* Correctly provide EditorConfig property types for Ktlint ([#2052](https://github.com/diffplug/spotless/issues/2052))
1920
* Made ShadowCopy (`npmInstallCache`) more robust by re-creating the cache dir if it goes missing ([#1984](https://github.com/diffplug/spotless/issues/1984),[2096](https://github.com/diffplug/spotless/pull/2096))
2021
* scalafmt.conf fileOverride section now works correctly ([#1854](https://github.com/diffplug/spotless/pull/1854))
2122
* Fix stdin pipe is being closed exception on Windows for large .proto files ([#2147](https://github.com/diffplug/spotless/issues/2147))
23+
* Reworked ShadowCopy (`npmInstallCache`) to use atomic filesystem operations, resolving several race conditions that could arise ([#2151](https://github.com/diffplug/spotless/pull/2151))
2224
### Changes
2325
* Bump default `cleanthat` version to latest `2.16` -> `2.20`. ([#1725](https://github.com/diffplug/spotless/pull/1725))
2426
* Bump default `gherkin-utils` version to latest `8.0.2` -> `9.0.0`. ([#1703](https://github.com/diffplug/spotless/pull/1703))

gradle/wrapper/gradle-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
44
networkTimeout=10000
55
validateDistributionUrl=true
66
zipStoreBase=GRADLE_USER_HOME

gradlew

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
# Darwin, MinGW, and NonStop.
5656
#
5757
# (3) This script is generated from the Groovy template
58-
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
58+
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
5959
# within the Gradle project.
6060
#
6161
# You can find Gradle at https://github.com/gradle/gradle/.

lib/src/compatKtLint1Dot0Dot0/java/com/diffplug/spotless/glue/ktlint/compat/KtLintCompat1Dot0Dot0Adapter.java

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -93,20 +93,21 @@ public String format(
9393
.flatMap(loader -> loader.get().getRuleProviders().stream())
9494
.collect(Collectors.toUnmodifiableSet());
9595

96-
EditorConfigOverride editorConfigOverride;
97-
if (editorConfigOverrideMap.isEmpty()) {
98-
editorConfigOverride = EditorConfigOverride.Companion.getEMPTY_EDITOR_CONFIG_OVERRIDE();
99-
} else {
100-
editorConfigOverride = createEditorConfigOverride(allRuleProviders.stream().map(
101-
RuleProvider::createNewRuleInstance).collect(Collectors.toList()),
102-
editorConfigOverrideMap);
103-
}
10496
EditorConfigDefaults editorConfig;
10597
if (editorConfigPath == null || !Files.exists(editorConfigPath)) {
10698
editorConfig = EditorConfigDefaults.Companion.getEMPTY_EDITOR_CONFIG_DEFAULTS();
10799
} else {
108100
editorConfig = EditorConfigDefaults.Companion.load(editorConfigPath, RuleProviderKt.propertyTypes(allRuleProviders));
109101
}
102+
EditorConfigOverride editorConfigOverride;
103+
if (editorConfigOverrideMap.isEmpty()) {
104+
editorConfigOverride = EditorConfigOverride.Companion.getEMPTY_EDITOR_CONFIG_OVERRIDE();
105+
} else {
106+
editorConfigOverride = createEditorConfigOverride(
107+
editorConfig,
108+
allRuleProviders.stream().map(RuleProvider::createNewRuleInstance).collect(Collectors.toList()),
109+
editorConfigOverrideMap);
110+
}
110111

111112
return new KtLintRuleEngine(
112113
allRuleProviders,
@@ -120,7 +121,7 @@ public String format(
120121
/**
121122
* Create EditorConfigOverride from user provided parameters.
122123
*/
123-
private static EditorConfigOverride createEditorConfigOverride(final List<Rule> rules, Map<String, Object> editorConfigOverrideMap) {
124+
private static EditorConfigOverride createEditorConfigOverride(final EditorConfigDefaults editorConfig, final List<Rule> rules, Map<String, Object> editorConfigOverrideMap) {
124125
// Get properties from rules in the rule sets
125126
Stream<EditorConfigProperty<?>> ruleProperties = rules.stream()
126127
.flatMap(rule -> rule.getUsesEditorConfigProperties().stream());
@@ -132,7 +133,9 @@ private static EditorConfigOverride createEditorConfigOverride(final List<Rule>
132133
.collect(Collectors.toMap(EditorConfigProperty::getName, property -> property));
133134

134135
// The default style had been changed from intellij_idea to ktlint_official in version 1.0.0
135-
if (!editorConfigOverrideMap.containsKey("ktlint_code_style")) {
136+
boolean isCodeStyleDefinedInEditorConfig = editorConfig.getValue().getSections().stream()
137+
.anyMatch(section -> section.getProperties().containsKey("ktlint_code_style"));
138+
if (!isCodeStyleDefinedInEditorConfig && !editorConfigOverrideMap.containsKey("ktlint_code_style")) {
136139
editorConfigOverrideMap.put("ktlint_code_style", "intellij_idea");
137140
}
138141

lib/src/main/java/com/diffplug/spotless/npm/ShadowCopy.java

Lines changed: 50 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,17 @@
1717

1818
import java.io.File;
1919
import java.io.IOException;
20+
import java.nio.file.AtomicMoveNotSupportedException;
21+
import java.nio.file.DirectoryNotEmptyException;
2022
import java.nio.file.FileAlreadyExistsException;
2123
import java.nio.file.FileSystemException;
2224
import java.nio.file.FileVisitResult;
2325
import java.nio.file.Files;
2426
import java.nio.file.Path;
2527
import java.nio.file.Paths;
2628
import java.nio.file.SimpleFileVisitor;
29+
import java.nio.file.StandardCopyOption;
2730
import java.nio.file.attribute.BasicFileAttributes;
28-
import java.time.Duration;
29-
import java.util.concurrent.TimeoutException;
3031
import java.util.function.Supplier;
3132

3233
import javax.annotation.Nonnull;
@@ -36,6 +37,8 @@
3637

3738
import com.diffplug.spotless.ThrowingEx;
3839

40+
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
41+
3942
class ShadowCopy {
4043

4144
private static final Logger logger = LoggerFactory.getLogger(ShadowCopy.class);
@@ -55,70 +58,67 @@ private File shadowCopyRoot() {
5558
}
5659

5760
public void addEntry(String key, File orig) {
58-
// prevent concurrent adding of entry with same key
59-
if (!reserveSubFolder(key)) {
60-
logger.debug("Shadow copy entry already in progress: {}. Awaiting finalization.", key);
61+
File target = entry(key, orig.getName());
62+
if (target.exists()) {
63+
logger.debug("Shadow copy entry already exists, not overwriting: {}", key);
64+
} else {
6165
try {
62-
NpmResourceHelper.awaitFileDeleted(markerFilePath(key).toFile(), Duration.ofSeconds(120));
63-
} catch (TimeoutException e) {
64-
throw new RuntimeException(e);
66+
storeEntry(key, orig, target);
67+
} catch (Throwable ex) {
68+
// Log but don't fail
69+
logger.warn("Unable to store cache entry for {}", key, ex);
6570
}
6671
}
72+
}
73+
74+
@SuppressFBWarnings("NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE")
75+
private void storeEntry(String key, File orig, File target) throws IOException {
76+
// Create a temp directory in the same directory as target
77+
Files.createDirectories(target.toPath().getParent());
78+
Path tempDirectory = Files.createTempDirectory(target.toPath().getParent(), key);
79+
logger.debug("Will store entry {} to temporary directory {}, which is a sibling of the ultimate target {}", orig, tempDirectory, target);
80+
6781
try {
68-
storeEntry(key, orig);
82+
// Copy orig to temp dir
83+
Files.walkFileTree(orig.toPath(), new CopyDirectoryRecursively(tempDirectory, orig.toPath()));
84+
try {
85+
logger.debug("Finished storing entry {}. Atomically moving temporary directory {} into final place {}", key, tempDirectory, target);
86+
// Atomically rename the completed cache entry into place
87+
Files.move(tempDirectory, target.toPath(), StandardCopyOption.ATOMIC_MOVE);
88+
} catch (FileAlreadyExistsException | DirectoryNotEmptyException e) {
89+
// Someone already beat us to it
90+
logger.debug("Shadow copy entry now exists, not overwriting: {}", key);
91+
} catch (AtomicMoveNotSupportedException e) {
92+
logger.warn("The filesystem at {} does not support atomic moves. Spotless cannot safely cache on such a system due to race conditions. Caching has been skipped.", target.toPath().getParent(), e);
93+
}
6994
} finally {
70-
cleanupReservation(key);
95+
// Best effort to clean up
96+
if (Files.exists(tempDirectory)) {
97+
try {
98+
Files.walkFileTree(tempDirectory, new DeleteDirectoryRecursively());
99+
} catch (Throwable ex) {
100+
logger.warn("Ignoring error while cleaning up temporary copy", ex);
101+
}
102+
}
71103
}
72104
}
73105

74106
public File getEntry(String key, String fileName) {
75107
return entry(key, fileName);
76108
}
77109

78-
private void storeEntry(String key, File orig) {
79-
File target = entry(key, orig.getName());
80-
if (target.exists()) {
81-
logger.debug("Shadow copy entry already exists: {}", key);
82-
// delete directory "target" recursively
83-
// https://stackoverflow.com/questions/3775694/deleting-folder-from-java
84-
ThrowingEx.run(() -> Files.walkFileTree(target.toPath(), new DeleteDirectoryRecursively()));
85-
}
86-
// copy directory "orig" to "target" using hard links if possible or a plain copy otherwise
87-
ThrowingEx.run(() -> Files.walkFileTree(orig.toPath(), new CopyDirectoryRecursively(target, orig)));
88-
}
89-
90-
private void cleanupReservation(String key) {
91-
ThrowingEx.run(() -> Files.delete(markerFilePath(key)));
92-
}
93-
94-
private Path markerFilePath(String key) {
95-
return Paths.get(shadowCopyRoot().getAbsolutePath(), key + ".marker");
96-
}
97-
98110
private File entry(String key, String origName) {
99111
return Paths.get(shadowCopyRoot().getAbsolutePath(), key, origName).toFile();
100112
}
101113

102-
private boolean reserveSubFolder(String key) {
103-
// put a marker file named "key".marker in "shadowCopyRoot" to make sure no other process is using it or return false if it already exists
104-
try {
105-
Files.createFile(Paths.get(shadowCopyRoot().getAbsolutePath(), key + ".marker"));
106-
return true;
107-
} catch (FileAlreadyExistsException e) {
108-
return false;
109-
} catch (IOException e) {
110-
throw new RuntimeException(e);
111-
}
112-
}
113-
114114
public File copyEntryInto(String key, String origName, File targetParentFolder) {
115115
File target = Paths.get(targetParentFolder.getAbsolutePath(), origName).toFile();
116116
if (target.exists()) {
117117
logger.warn("Shadow copy destination already exists, deleting! {}: {}", key, target);
118118
ThrowingEx.run(() -> Files.walkFileTree(target.toPath(), new DeleteDirectoryRecursively()));
119119
}
120120
// copy directory "orig" to "target" using hard links if possible or a plain copy otherwise
121-
ThrowingEx.run(() -> Files.walkFileTree(entry(key, origName).toPath(), new CopyDirectoryRecursively(target, entry(key, origName))));
121+
ThrowingEx.run(() -> Files.walkFileTree(entry(key, origName).toPath(), new CopyDirectoryRecursively(target.toPath(), entry(key, origName).toPath())));
122122
return target;
123123
}
124124

@@ -127,20 +127,20 @@ public boolean entryExists(String key, String origName) {
127127
}
128128

129129
private static class CopyDirectoryRecursively extends SimpleFileVisitor<Path> {
130-
private final File target;
131-
private final File orig;
130+
private final Path target;
131+
private final Path orig;
132132

133133
private boolean tryHardLink = true;
134134

135-
public CopyDirectoryRecursively(File target, File orig) {
135+
public CopyDirectoryRecursively(Path target, Path orig) {
136136
this.target = target;
137137
this.orig = orig;
138138
}
139139

140140
@Override
141141
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
142142
// create directory on target
143-
Files.createDirectories(target.toPath().resolve(orig.toPath().relativize(dir)));
143+
Files.createDirectories(target.resolve(orig.relativize(dir)));
144144
return super.preVisitDirectory(dir, attrs);
145145
}
146146

@@ -149,7 +149,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
149149
// first try to hardlink, if that fails, copy
150150
if (tryHardLink) {
151151
try {
152-
Files.createLink(target.toPath().resolve(orig.toPath().relativize(file)), file);
152+
Files.createLink(target.resolve(orig.relativize(file)), file);
153153
return super.visitFile(file, attrs);
154154
} catch (UnsupportedOperationException | SecurityException | FileSystemException e) {
155155
logger.debug("Shadow copy entry does not support hard links: {}. Switching to 'copy'.", file, e);
@@ -160,11 +160,12 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
160160
}
161161
}
162162
// copy file to target
163-
Files.copy(file, target.toPath().resolve(orig.toPath().relativize(file)));
163+
Files.copy(file, target.resolve(orig.relativize(file)));
164164
return super.visitFile(file, attrs);
165165
}
166166
}
167167

168+
// https://stackoverflow.com/questions/3775694/deleting-folder-from-java
168169
private static class DeleteDirectoryRecursively extends SimpleFileVisitor<Path> {
169170
@Override
170171
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {

plugin-gradle/CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
99
* Respect `.editorconfig` settings for formatting shell via `shfmt` ([#2031](https://github.com/diffplug/spotless/pull/2031))
1010
* Add support for formatting and sorting Maven POMs ([#2082](https://github.com/diffplug/spotless/issues/2082))
1111
### Fixed
12+
* Check if ktlint_code_style is set in .editorconfig before overriding it ([#2143](https://github.com/diffplug/spotless/issues/2143))
1213
* Full no-asterisk support for configuration cache ([#2088](https://github.com/diffplug/spotless/pull/2088) closes [#1274](https://github.com/diffplug/spotless/issues/1274) and [#987](https://github.com/diffplug/spotless/issues/987)).
1314
* Ignore system git config when running tests ([#1990](https://github.com/diffplug/spotless/issues/1990))
1415
* Correctly provide EditorConfig property types for Ktlint ([#2052](https://github.com/diffplug/spotless/issues/2052))
1516
* Fixed memory leak introduced in 6.21.0 ([#2067](https://github.com/diffplug/spotless/issues/2067))
1617
* Made ShadowCopy (`npmInstallCache`) more robust by re-creating the cache dir if it goes missing ([#1984](https://github.com/diffplug/spotless/issues/1984),[2096](https://github.com/diffplug/spotless/pull/2096))
1718
* scalafmt.conf fileOverride section now works correctly ([#1854](https://github.com/diffplug/spotless/pull/1854))
1819
* Fix stdin pipe is being closed exception on Windows for large .proto files ([#2147](https://github.com/diffplug/spotless/issues/2147))
20+
* Reworked ShadowCopy (`npmInstallCache`) to use atomic filesystem operations, resolving several race conditions that could arise ([#2151](https://github.com/diffplug/spotless/pull/2151))
1921
### Changes
2022
* Bump default `cleanthat` version to latest `2.16` -> `2.20`. ([#1725](https://github.com/diffplug/spotless/pull/1725))
2123
* Bump default `gherkin-utils` version to latest `8.0.2` -> `9.0.0`. ([#1703](https://github.com/diffplug/spotless/pull/1703))

plugin-gradle/src/test/java/com/diffplug/gradle/spotless/KotlinExtensionTest.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2023 DiffPlug
2+
* Copyright 2016-2024 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -127,6 +127,25 @@ void testReadCodeStyleFromEditorConfigFile() throws IOException {
127127
checkKtlintOfficialStyle();
128128
}
129129

130+
@Test
131+
void testEditorConfigOverrideWithUnsetCodeStyleDoesNotOverrideEditorConfigCodeStyleWithDefault() throws IOException {
132+
setFile(".editorconfig").toResource("kotlin/ktlint/ktlint_official/.editorconfig");
133+
setFile("build.gradle").toLines(
134+
"plugins {",
135+
" id 'org.jetbrains.kotlin.jvm' version '1.6.21'",
136+
" id 'com.diffplug.spotless'",
137+
"}",
138+
"repositories { mavenCentral() }",
139+
"spotless {",
140+
" kotlin {",
141+
" ktlint().editorConfigOverride([",
142+
" ktlint_test_key: true,",
143+
" ])",
144+
" }",
145+
"}");
146+
checkKtlintOfficialStyle();
147+
}
148+
130149
@Test
131150
void testSetEditorConfigCanOverrideEditorConfigFile() throws IOException {
132151
setFile(".editorconfig").toResource("kotlin/ktlint/intellij_idea/.editorconfig");

plugin-maven/CHANGES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
77
* Respect `.editorconfig` settings for formatting shell via `shfmt` ([#2031](https://github.com/diffplug/spotless/pull/2031))
88
* Skip execution in M2E (incremental) builds by default ([#1814](https://github.com/diffplug/spotless/issues/1814), [#2037](https://github.com/diffplug/spotless/issues/2037))
99
### Fixed
10+
* Check if ktlint_code_style is set in .editorconfig before overriding it ([#2143](https://github.com/diffplug/spotless/issues/2143))
11+
* Default EditorConfig path to ".editorconfig" ([#2143](https://github.com/diffplug/spotless/issues/2143))
1012
* Ignore system git config when running tests ([#1990](https://github.com/diffplug/spotless/issues/1990))
1113
* Correctly provide EditorConfig property types for Ktlint ([#2052](https://github.com/diffplug/spotless/issues/2052))
1214
* Made ShadowCopy (`npmInstallCache`) more robust by re-creating the cache dir if it goes missing ([#1984](https://github.com/diffplug/spotless/issues/1984),[2096](https://github.com/diffplug/spotless/pull/2096))
1315
* scalafmt.conf fileOverride section now works correctly ([#1854](https://github.com/diffplug/spotless/pull/1854))
1416
* Fix stdin pipe is being closed exception on Windows for large .proto files ([#2147](https://github.com/diffplug/spotless/issues/2147))
17+
* Reworked ShadowCopy (`npmInstallCache`) to use atomic filesystem operations, resolving several race conditions that could arise ([#2151](https://github.com/diffplug/spotless/pull/2151))
1518
### Changes
1619
* Bump default `cleanthat` version to latest `2.16` -> `2.20`. ([#1725](https://github.com/diffplug/spotless/pull/1725))
1720
* Bump default `gherkin-utils` version to latest `8.0.2` -> `9.0.0`. ([#1703](https://github.com/diffplug/spotless/pull/1703))

plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Ktlint.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2023 DiffPlug
2+
* Copyright 2016-2024 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
1515
*/
1616
package com.diffplug.spotless.maven.kotlin;
1717

18+
import java.io.File;
1819
import java.util.Collections;
1920
import java.util.HashMap;
2021
import java.util.List;
@@ -30,6 +31,8 @@
3031
import com.diffplug.spotless.maven.FormatterStepFactory;
3132

3233
public class Ktlint implements FormatterStepFactory {
34+
private static final File defaultEditorConfig = new File(".editorconfig");
35+
3336
@Parameter
3437
private String version;
3538
@Parameter
@@ -43,6 +46,9 @@ public class Ktlint implements FormatterStepFactory {
4346
public FormatterStep newFormatterStep(final FormatterStepConfig stepConfig) {
4447
String ktlintVersion = version != null ? version : KtLintStep.defaultVersion();
4548
FileSignature configPath = null;
49+
if (editorConfigPath == null && defaultEditorConfig.exists()) {
50+
editorConfigPath = defaultEditorConfig.getPath();
51+
}
4652
if (editorConfigPath != null) {
4753
configPath = ThrowingEx.get(() -> FileSignature.signAsList(stepConfig.getFileLocator().locateFile(editorConfigPath)));
4854
}

plugin-maven/src/test/java/com/diffplug/spotless/maven/kotlin/KtlintTest.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2023 DiffPlug
2+
* Copyright 2016-2024 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -55,6 +55,17 @@ void testReadCodeStyleFromEditorConfigFile() throws Exception {
5555
checkKtlintOfficialStyle();
5656
}
5757

58+
@Test
59+
void testEditorConfigOverrideWithUnsetCodeStyleDoesNotOverrideEditorConfigCodeStyleWithDefault() throws Exception {
60+
setFile(".editorconfig").toResource("kotlin/ktlint/ktlint_official/.editorconfig");
61+
writePomWithKotlinSteps("<ktlint>\n" +
62+
" <editorConfigOverride>\n" +
63+
" <ktlint_test_key>true</ktlint_test_key>\n" +
64+
" </editorConfigOverride>\n" +
65+
"</ktlint>");
66+
checkKtlintOfficialStyle();
67+
}
68+
5869
@Test
5970
void testSetEditorConfigCanOverrideEditorConfigFile() throws Exception {
6071
setFile(".editorconfig").toResource("kotlin/ktlint/intellij_idea/.editorconfig");

0 commit comments

Comments
 (0)