Skip to content

Commit

Permalink
Maven IDE hook (#1782)
Browse files Browse the repository at this point in the history
  • Loading branch information
nedtwigg authored Sep 28, 2023
2 parents c4e5be7 + 5ddf6e0 commit 5d9f3b4
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 0 deletions.
2 changes: 2 additions & 0 deletions plugin-maven/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (

## [Unreleased]
### Added
* Add `-DspotlessIdeHook` that provides the ability to apply Spotless exclusively to a specified file. It accepts the absolute path of the file. ([#1782](https://github.com/diffplug/spotless/pull/1782))
* BETA, subject to change until we have proven compatibility with some IDE plugins.
* Added support for `google-java-format`'s `skip-javadoc-formatting` option ([#1793](https://github.com/diffplug/spotless/pull/1793))
* Added support for biome. The Rome project [was renamed to Biome](https://biomejs.dev/blog/annoucing-biome/).
The configuration is still the same, but you should switch to the new `<biome>` tag and adjust
Expand Down
1 change: 1 addition & 0 deletions plugin-maven/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ dependencies {
compileOnly "org.eclipse.aether:aether-api:${VER_ECLIPSE_AETHER}"

implementation "com.diffplug.durian:durian-core:${VER_DURIAN}"
implementation "com.diffplug.durian:durian-io:${VER_DURIAN}"
implementation "com.diffplug.durian:durian-collect:${VER_DURIAN}"
implementation("org.codehaus.plexus:plexus-resources:${VER_PLEXUS_RESOURCES}")
implementation "org.eclipse.jgit:org.eclipse.jgit:${VER_JGIT}"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright 2016-2023 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.maven;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;

import com.diffplug.common.base.Errors;
import com.diffplug.common.io.ByteStreams;
import com.diffplug.spotless.Formatter;
import com.diffplug.spotless.PaddedCell;

class IdeHook {

private static void dumpIsClean() {
System.err.println("IS CLEAN");
}

//No need to check ratchet (using isClean()) as it is performed in Gradle's IDE hook, since we have already gathered the available git files from ratchet.
static void performHook(Iterable<File> projectFiles, Formatter formatter, String path, boolean spotlessIdeHookUseStdIn, boolean spotlessIdeHookUseStdOut) {
File file = new File(path);
if (!file.isAbsolute()) {
System.err.println("Argument passed to spotlessIdeHook must be an absolute path");
return;
}

if (!projectContainsFile(projectFiles, file)) {
return;
}

try {
byte[] bytes;
if (spotlessIdeHookUseStdIn) {
bytes = ByteStreams.toByteArray(System.in);
} else {
bytes = Files.readAllBytes(file.toPath());
}
PaddedCell.DirtyState dirty = PaddedCell.calculateDirtyState(formatter, file, bytes);
if (dirty.isClean()) {
dumpIsClean();
} else if (dirty.didNotConverge()) {
System.err.println("DID NOT CONVERGE");
System.err.println("See details https://github.com/diffplug/spotless/blob/main/PADDEDCELL.md");
} else {
System.err.println("IS DIRTY");
if (spotlessIdeHookUseStdOut) {
dirty.writeCanonicalTo(System.out);
} else {
dirty.writeCanonicalTo(file);
}
}
} catch (IOException e) {
e.printStackTrace(System.err);
throw Errors.asRuntime(e);
} finally {
System.err.close();
System.out.close();
}
}

private static boolean projectContainsFile(Iterable<File> projectFiles, File file) {
for (File projectFile : projectFiles) {
if (projectFile.equals(file)) {
return true;
}
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

import com.diffplug.spotless.Formatter;
import com.diffplug.spotless.PaddedCell;
Expand All @@ -31,8 +32,22 @@
@Mojo(name = AbstractSpotlessMojo.GOAL_APPLY, threadSafe = true)
public class SpotlessApplyMojo extends AbstractSpotlessMojo {

@Parameter(property = "spotlessIdeHook")
private String spotlessIdeHook;

@Parameter(property = "spotlessIdeHookUseStdIn")
private boolean spotlessIdeHookUseStdIn;

@Parameter(property = "spotlessIdeHookUseStdOut")
private boolean spotlessIdeHookUseStdOut;

@Override
protected void process(Iterable<File> files, Formatter formatter, UpToDateChecker upToDateChecker) throws MojoExecutionException {
if (isIdeHook()) {
IdeHook.performHook(files, formatter, spotlessIdeHook, spotlessIdeHookUseStdIn, spotlessIdeHookUseStdOut);
return;
}

ImpactedFilesTracker counter = new ImpactedFilesTracker();

for (File file : files) {
Expand Down Expand Up @@ -69,4 +84,8 @@ protected void process(Iterable<File> files, Formatter formatter, UpToDateChecke
getLog().debug(String.format("Spotless.%s has no target files. Examine your `<includes>`: https://github.com/diffplug/spotless/tree/main/plugin-maven#quickstart", formatter.getName()));
}
}

private boolean isIdeHook() {
return !(spotlessIdeHook == null || spotlessIdeHook.isEmpty());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright 2016-2023 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.maven;

import java.io.File;
import java.io.IOException;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import com.diffplug.spotless.ProcessRunner;

class IdeHookTest extends MavenIntegrationHarness {
private String output, error;
private File dirty, clean, diverge, outofbounds;

@BeforeEach
void before() throws IOException {
writePomWithFormatSteps("<includes>\n" +
" <include>DIRTY.md</include>\n" +
" <include>CLEAN.md</include>\n" +
" </includes>\n" +
" <replace>\n" +
" <name>Greetings to Mars</name>\n" +
" <search>World</search>\n" +
" <replacement>Mars</replacement>\n" +
" </replace>");

dirty = setFile("DIRTY.md").toContent("World");
clean = setFile("CLEAN.md").toContent("Mars");
outofbounds = setFile("OUTOFBOUNDS.md").toContent("Mars");
;
}

private void runWith(String... arguments) throws IOException, InterruptedException {
ProcessRunner.Result result = mavenRunner()
.withArguments(arguments)
.runNoError();

this.output = result.stdOutUtf8();
this.error = result.stdErrUtf8();
}

@Test
void dirty() throws IOException, InterruptedException {
runWith("spotless:apply", "--quiet", "-DspotlessIdeHook=\"" + dirty.getAbsolutePath() + "\"", "-DspotlessIdeHookUseStdOut=true");
Assertions.assertThat(output).isEqualTo("Mars");
Assertions.assertThat(error).startsWith("IS DIRTY");
}

@Test
void clean() throws IOException, InterruptedException {
runWith("spotless:apply", "--quiet", "-DspotlessIdeHook=" + clean.getAbsolutePath(), "-DspotlessIdeHookUseStdOut=true");
Assertions.assertThat(output).isEmpty();
Assertions.assertThat(error).startsWith("IS CLEAN");
}

@Test
void outofbounds() throws IOException, InterruptedException {
runWith("spotless:apply", "--quiet", "-DspotlessIdeHook=" + outofbounds.getAbsolutePath(), "-DspotlessIdeHookUseStdOut=true");
Assertions.assertThat(output).isEmpty();
Assertions.assertThat(error).isEmpty();
}

@Test
void notAbsolute() throws IOException, InterruptedException {
runWith("spotless:apply", "--quiet", "-DspotlessIdeHook=\"pom.xml\"", "-DspotlessIdeHookUseStdOut=true");
Assertions.assertThat(output).isEmpty();
Assertions.assertThat(error).contains("Argument passed to spotlessIdeHook must be an absolute path");
}
}

0 comments on commit 5d9f3b4

Please sign in to comment.