Skip to content

Commit 792d0f2

Browse files
authored
Add lint suppression API to maven (#2629)
2 parents bbe2ebc + 9e246d5 commit 792d0f2

File tree

19 files changed

+392
-71
lines changed

19 files changed

+392
-71
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
2626
* `GitPrePushHookInstaller` uses a lock to run gracefully if it is called many times in parallel. ([#2570](https://github.com/diffplug/spotless/pull/2570))
2727
### Added
2828
* Add a `lint` mode to `ReplaceRegexStep` ([#2571](https://github.com/diffplug/spotless/pull/2571))
29+
* `LintSuppression` now enforces unix-style paths in its `setPath` and `relativizeAsUnix` methods. ([#2629](https://github.com/diffplug/spotless/pull/2629))
2930

3031
## [3.3.1] - 2025-07-21
3132
### Fixed

lib-extra/src/main/java/com/diffplug/spotless/extra/integration/DiffMessageFormatter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2024 DiffPlug
2+
* Copyright 2016-2025 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.
@@ -292,7 +292,7 @@ private static Map.Entry<Integer, String> diffWhitespaceLineEndings(String dirty
292292
}
293293

294294
private static int getLineOfFirstDifference(EditList edits) {
295-
return edits.stream().mapToInt(Edit::getBeginA).min().getAsInt();
295+
return edits.stream().mapToInt(Edit::getBeginA).min().orElse(0);
296296
}
297297

298298
private static final CharMatcher NEWLINE_MATCHER = CharMatcher.is('\n');

lib/src/main/java/com/diffplug/spotless/LintSuppression.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2024 DiffPlug
2+
* Copyright 2024-2025 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,8 +15,11 @@
1515
*/
1616
package com.diffplug.spotless;
1717

18+
import java.io.File;
1819
import java.util.Objects;
1920

21+
import javax.annotation.Nullable;
22+
2023
public class LintSuppression implements java.io.Serializable {
2124
private static final long serialVersionUID = 1L;
2225

@@ -30,6 +33,9 @@ public String getPath() {
3033
}
3134

3235
public void setPath(String path) {
36+
if (path.indexOf('\\') != -1) {
37+
throw new IllegalArgumentException("Path must use only unix style path separator `/`, this was " + path);
38+
}
3339
this.path = Objects.requireNonNull(path);
3440
}
3541

@@ -90,4 +96,20 @@ public String toString() {
9096
", code='" + shortCode + '\'' +
9197
'}';
9298
}
99+
100+
/**
101+
* Returns the relative path between root and dest, or null if dest is not a
102+
* child of root. Guaranteed to only have unix-separators.
103+
*/
104+
public static @Nullable String relativizeAsUnix(File root, File dest) {
105+
String rootPath = root.getAbsolutePath();
106+
String destPath = dest.getAbsolutePath();
107+
if (!destPath.startsWith(rootPath)) {
108+
return null;
109+
} else {
110+
String relativized = destPath.substring(rootPath.length());
111+
String unixified = relativized.replace('\\', '/');
112+
return unixified.startsWith("/") ? unixified.substring(1) : unixified;
113+
}
114+
}
93115
}

lib/src/main/java/com/diffplug/spotless/generic/ReplaceRegexStep.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,12 @@ public List<Lint> lint(String raw, File file) {
9090
var matcher = regex.matcher(raw);
9191
while (matcher.find()) {
9292
int line = 1 + (int) raw.codePoints().limit(matcher.start()).filter(c -> c == '\n').count();
93-
lints.add(Lint.atLine(line, matcher.group(0), lintDetail));
93+
String errorCode = matcher.group(0).trim();
94+
int firstNewline = errorCode.indexOf("\n");
95+
if (firstNewline != -1) {
96+
errorCode = errorCode.substring(0, firstNewline);
97+
}
98+
lints.add(Lint.atLine(line, errorCode, lintDetail));
9499
}
95100
return lints;
96101
}

plugin-gradle/CHANGES.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
66
### Changed
77
* **BREAKING** Bump the required Gradle to `7.3` and required Java to `17`. ([#2375](https://github.com/diffplug/spotless/issues/2375), [#2540](https://github.com/diffplug/spotless/pull/2540))
88
* **BREAKING** `spotlessInstallGitPrePushHook` task is now installed only on the root project. ([#2570](https://github.com/diffplug/spotless/pull/2570))
9+
* **BREAKING** `LintSuppression` now enforces unix-style paths in its `setPath` method. ([#2629](https://github.com/diffplug/spotless/pull/2629))
910
* Running `spotlessCheck` with violations unilaterally produces the error message `Run './gradlew spotlessApply' to fix these violations`. ([#2592](https://github.com/diffplug/spotless/issues/2592))
1011
* Bump JGit from `6.10.1` to `7.3.0` ([#2257](https://github.com/diffplug/spotless/pull/2257))
1112
* Adds support for worktrees (fixes [#1765](https://github.com/diffplug/spotless/issues/1765))
@@ -16,7 +17,6 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
1617
* **BREAKING** use `TrailingCommaManagementStrategy` enum instead of `manageTrailingCommas` boolean configuration option
1718
* Bump default `ktlint` version to latest `1.5.0` -> `1.7.1`. ([#2555](https://github.com/diffplug/spotless/pull/2555))
1819
* Bump default `palantir-java-format` version to latest `2.57.0` -> `2.71.0`.
19-
2020
### Fixed
2121
* Respect system gitconfig when performing git operations ([#2404](https://github.com/diffplug/spotless/issues/2404))
2222
* Fix `spaceBeforeSeparator` in Jackson formatter. ([#2103](https://github.com/diffplug/spotless/pull/2103))

plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -347,27 +347,12 @@ private final FileCollection parseTargetIsExclude(Object target, boolean isExclu
347347
}
348348

349349
private static void relativizeIfSubdir(List<String> relativePaths, File root, File dest) {
350-
String relativized = relativize(root, dest);
350+
String relativized = LintSuppression.relativizeAsUnix(root, dest);
351351
if (relativized != null) {
352352
relativePaths.add(relativized);
353353
}
354354
}
355355

356-
/**
357-
* Returns the relative path between root and dest, or null if dest is not a
358-
* child of root.
359-
*/
360-
static @Nullable String relativize(File root, File dest) {
361-
String rootPath = root.getAbsolutePath();
362-
String destPath = dest.getAbsolutePath();
363-
if (!destPath.startsWith(rootPath)) {
364-
return null;
365-
} else {
366-
String relativized = destPath.substring(rootPath.length());
367-
return relativized.startsWith("/") || relativized.startsWith("\\") ? relativized.substring(1) : relativized;
368-
}
369-
}
370-
371356
/** The steps that need to be added. */
372357
protected final List<FormatterStep> steps = new ArrayList<>();
373358

plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessTaskImpl.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2024 DiffPlug
2+
* Copyright 2016-2025 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.
@@ -45,6 +45,7 @@
4545
import com.diffplug.spotless.Formatter;
4646
import com.diffplug.spotless.Lint;
4747
import com.diffplug.spotless.LintState;
48+
import com.diffplug.spotless.LintSuppression;
4849
import com.diffplug.spotless.extra.GitRatchet;
4950

5051
@CacheableTask
@@ -101,7 +102,7 @@ public void performAction(InputChanges inputs) throws Exception {
101102
for (FileChange fileChange : inputs.getFileChanges(target)) {
102103
File input = fileChange.getFile();
103104
File projectDir = getProjectDir().get().getAsFile();
104-
String relativePath = FormatExtension.relativize(projectDir, input);
105+
String relativePath = LintSuppression.relativizeAsUnix(projectDir, input);
105106
if (relativePath == null) {
106107
throw new IllegalArgumentException(StringPrinter.buildString(printer -> {
107108
printer.println("Spotless error! All target files must be within the project dir.");

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2021 DiffPlug
2+
* Copyright 2016-2025 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,8 +15,6 @@
1515
*/
1616
package com.diffplug.gradle.spotless;
1717

18-
import static com.diffplug.gradle.spotless.FormatExtension.relativize;
19-
2018
import java.io.File;
2119
import java.io.IOException;
2220

@@ -26,6 +24,7 @@
2624
import org.junit.jupiter.api.BeforeEach;
2725
import org.junit.jupiter.api.Test;
2826

27+
import com.diffplug.spotless.LintSuppression;
2928
import com.diffplug.spotless.ResourceHarness;
3029
import com.diffplug.spotless.TestProvisioner;
3130

@@ -51,7 +50,7 @@ void absolutePathDoesntWork() throws IOException {
5150
void relativePathDoes() throws IOException {
5251
File someFile = setFile("someFolder/someFile").toContent("");
5352
File someFolder = someFile.getParentFile();
54-
fileTree.exclude(relativize(rootFolder(), someFolder));
53+
fileTree.exclude(LintSuppression.relativizeAsUnix(rootFolder(), someFolder));
5554
Assertions.assertThat(fileTree).containsExactlyInAnyOrder();
5655
}
5756
}

plugin-maven/CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
1717
* Bump default `palantir-java-format` version to latest `2.57.0` -> `2.71.0`.
1818
### Fixed
1919
* Fix `spaceBeforeSeparator` in Jackson formatter. ([#2103](https://github.com/diffplug/spotless/pull/2103))
20+
### Added
21+
* `<lintSupressions>` API ([#2309](https://github.com/diffplug/spotless/issues/2309))
2022

2123
## [2.46.1] - 2025-07-21
2224
### Fixed

plugin-maven/README.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1944,6 +1944,64 @@ By default, `spotless:check` is bound to the `verify` phase. You might want to
19441944
- set `-Dspotless.check.skip=true` at the command line
19451945
- set `spotless.check.skip` to `true` in the `<properties>` section of the `pom.xml`
19461946

1947+
### Suppressing lint errors
1948+
1949+
Sometimes Spotless will encounter lint errors that can't be auto-fixed. For example, if you run `mvn spotless:check`, you might see:
1950+
1951+
```
1952+
[ERROR] Unable to format file src/main/java/com/example/App.java
1953+
[ERROR] Step 'removeWildcardImports' found problem in 'App.java':
1954+
[ERROR] Do not use wildcard imports
1955+
```
1956+
1957+
To suppress these lints, you can use the `<lintSuppressions>` configuration:
1958+
1959+
```xml
1960+
<plugin>
1961+
<groupId>com.diffplug.spotless</groupId>
1962+
<artifactId>spotless-maven-plugin</artifactId>
1963+
<version>${spotless.version}</version>
1964+
<configuration>
1965+
<java>
1966+
<removeWildcardImports/>
1967+
</java>
1968+
<lintSuppressions>
1969+
<lintSuppression>
1970+
<path>src/main/java/com/example/App.java</path>
1971+
<step>removeWildcardImports</step>
1972+
<shortCode>*</shortCode>
1973+
</lintSuppression>
1974+
</lintSuppressions>
1975+
</configuration>
1976+
</plugin>
1977+
```
1978+
1979+
Each `<lintSuppression>` can match by:
1980+
- `<path>` - file path (supports wildcards like `*`)
1981+
- `<step>` - step name (supports wildcards like `*`)
1982+
- `<shortCode>` - specific error code (supports wildcards like `*`)
1983+
1984+
You can suppress multiple patterns:
1985+
1986+
```xml
1987+
<lintSuppressions>
1988+
<!-- Suppress all wildcard import errors in legacy code -->
1989+
<lintSuppression>
1990+
<path>src/main/java/com/example/legacy/*</path>
1991+
<step>removeWildcardImports</step>
1992+
<shortCode>*</shortCode>
1993+
</lintSuppression>
1994+
<!-- Suppress all errors from a specific step -->
1995+
<lintSuppression>
1996+
<path>*</path>
1997+
<step>removeWildcardImports</step>
1998+
<shortCode>*</shortCode>
1999+
</lintSuppression>
2000+
</lintSuppressions>
2001+
```
2002+
2003+
Spotless is primarily a formatter, _not_ a linter. In our opinion, a linter is just a broken formatter. But formatters do break sometimes, and representing these failures as lints that can be suppressed is more useful than just giving up.
2004+
19472005
<a name="preview"></a>
19482006

19492007
## How do I preview what `mvn spotless:apply` will do?

0 commit comments

Comments
 (0)