diff --git a/CHANGES.md b/CHANGES.md index 8293abcd22..dc040c9aa2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,8 @@ 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 +* New static method to `DiffMessageFormatter` which allows to retrieve diffs with their line numbers ([#1960](https://github.com/diffplug/spotless/issues/1960)) ### Changes * Use palantir-java-format 2.39.0 on Java 21. ([#1948](https://github.com/diffplug/spotless/pull/1948)) diff --git a/lib-extra/src/main/java/com/diffplug/spotless/extra/integration/DiffMessageFormatter.java b/lib-extra/src/main/java/com/diffplug/spotless/extra/integration/DiffMessageFormatter.java index d43478c0b6..9294055a4f 100644 --- a/lib-extra/src/main/java/com/diffplug/spotless/extra/integration/DiffMessageFormatter.java +++ b/lib-extra/src/main/java/com/diffplug/spotless/extra/integration/DiffMessageFormatter.java @@ -24,9 +24,11 @@ import java.nio.file.Path; import java.util.List; import java.util.ListIterator; +import java.util.Map; import java.util.Objects; import org.eclipse.jgit.diff.DiffFormatter; +import org.eclipse.jgit.diff.Edit; import org.eclipse.jgit.diff.EditList; import org.eclipse.jgit.diff.MyersDiff; import org.eclipse.jgit.diff.RawText; @@ -234,6 +236,19 @@ private void addIntendedLine(String indent, String line) { * sequence (\n, \r, \r\n). */ private String diff(File file) throws IOException { + return diff(formatter, file).getValue(); + } + + /** + * Returns a map entry with value being a git-style diff between the contents of the given file and what those contents would + * look like if formatted using the given formatter. Does not end with any newline + * sequence (\n, \r, \r\n). The key of the map entry is the 0-based line where the first difference occurred. + */ + public static Map.Entry diff(Formatter formatter, File file) throws IOException { + return diff(new CleanProviderFormatter(formatter), file); + } + + private static Map.Entry diff(CleanProvider formatter, File file) throws IOException { String raw = new String(Files.readAllBytes(file.toPath()), formatter.getEncoding()); String rawUnix = LineEnding.toUnix(raw); String formatted = formatter.getFormatted(file, rawUnix); @@ -248,13 +263,13 @@ private String diff(File file) throws IOException { } /** - * Returns a git-style diff between the two unix strings. + * Returns a map entry with value being a git-style diff between the two unix strings and key being the 0-based line of the first difference (in the dirty string) *

* Output has no trailing newlines. *

* Boolean args determine whether whitespace or line endings will be visible. */ - private static String diffWhitespaceLineEndings(String dirty, String clean, boolean whitespace, boolean lineEndings) throws IOException { + private static Map.Entry diffWhitespaceLineEndings(String dirty, String clean, boolean whitespace, boolean lineEndings) throws IOException { dirty = visibleWhitespaceLineEndings(dirty, whitespace, lineEndings); clean = visibleWhitespaceLineEndings(clean, whitespace, lineEndings); @@ -271,7 +286,11 @@ private static String diffWhitespaceLineEndings(String dirty, String clean, bool // we don't need the diff to show this, since we display newlines ourselves formatted = formatted.replace("\\ No newline at end of file\n", ""); - return NEWLINE_MATCHER.trimTrailingFrom(formatted); + return Map.entry(getLineOfFirstDifference(edits), NEWLINE_MATCHER.trimTrailingFrom(formatted)); + } + + private static int getLineOfFirstDifference(EditList edits) { + return edits.stream().mapToInt(Edit::getBeginA).min().getAsInt(); } private static final CharMatcher NEWLINE_MATCHER = CharMatcher.is('\n'); diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 4fab316049..55f451ad4e 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] +### Added +* M2E support: Emit file specific errors during incremental build. ([#1960](https://github.com/diffplug/spotless/issues/1960)) ### Changes * Use palantir-java-format 2.39.0 on Java 21. ([#1948](https://github.com/diffplug/spotless/pull/1948)) diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/SpotlessCheckMojo.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/SpotlessCheckMojo.java index 03e55e224a..cc83b3f3c9 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/SpotlessCheckMojo.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/SpotlessCheckMojo.java @@ -19,10 +19,12 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Map; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; +import org.sonatype.plexus.build.incremental.BuildContext; import com.diffplug.spotless.Formatter; import com.diffplug.spotless.PaddedCell; @@ -54,13 +56,17 @@ protected void process(Iterable files, Formatter formatter, UpToDateChecke PaddedCell.DirtyState dirtyState = PaddedCell.calculateDirtyState(formatter, file); if (!dirtyState.isClean() && !dirtyState.didNotConverge()) { problemFiles.add(file); + if (buildContext.isIncremental()) { + Map.Entry diffEntry = DiffMessageFormatter.diff(formatter, file); + buildContext.addMessage(file, diffEntry.getKey() + 1, 0, diffEntry.getValue(), BuildContext.SEVERITY_ERROR, null); + } counter.cleaned(); } else { counter.checkedButAlreadyClean(); upToDateChecker.setUpToDate(file.toPath()); } } catch (IOException | RuntimeException e) { - throw new MojoExecutionException("Unable to format file " + file, e); + throw new MojoExecutionException("Unable to check file " + file, e); } }