diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 9c741a0aea..d22b01559f 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -3,6 +3,7 @@ ### Version 1.22.0-SNAPSHOT - TBD ([javadoc](https://diffplug.github.io/spotless/javadoc/spotless-maven-plugin/snapshot/), [snapshot](https://oss.sonatype.org/content/repositories/snapshots/com/diffplug/spotless/spotless-maven-plugin/)) * Updated default eclipse-cdt from 4.7.3a to 4.11.0 ([#390](https://github.com/diffplug/spotless/pull/390)). +* Added `-DspotlessFiles` switch to allow targeting specific files ([#392](https://github.com/diffplug/spotless/pull/392)) ### Version 1.21.1 - March 29th 2019 ([javadoc](https://diffplug.github.io/spotless/javadoc/spotless-maven-plugin/1.21.1/), [jcenter](https://bintray.com/diffplug/opensource/spotless-maven-plugin/1.21.1)) diff --git a/plugin-maven/README.md b/plugin-maven/README.md index b1ee9d8bcd..fca10012d6 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -377,6 +377,16 @@ By default, `spotless:check` is bound to the `verify` phase. You might want to +## Can I apply Spotless to specific files? + +You can target specific files by setting the `spotlessFiles` project property to a comma-separated list of file patterns: + +``` +cmd> mvn spotless:apply -DspotlessFiles=my/file/pattern.java,more/generic/.*-pattern.java +``` + +The patterns are matched using `String#matches(String)` against the absolute file path. + ## Example configurations (from real-world projects) - [Apache Avro](https://github.com/apache/avro/blob/8026c8ffe4ef67ab419dba73910636bf2c1a691c/lang/java/pom.xml#L307-L334) diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/AbstractSpotlessMojo.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/AbstractSpotlessMojo.java index 0d2753ca94..f045348117 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/AbstractSpotlessMojo.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/AbstractSpotlessMojo.java @@ -20,6 +20,9 @@ import java.io.File; import java.io.IOException; import java.util.*; +import java.util.function.Predicate; +import java.util.regex.Pattern; +import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.maven.plugin.AbstractMojo; @@ -100,6 +103,9 @@ public abstract class AbstractSpotlessMojo extends AbstractMojo { @Deprecated private com.diffplug.spotless.maven.css.Css css; + @Parameter(property = "spotlessFiles") + private String filePatterns; + protected abstract void process(List files, Formatter formatter) throws MojoExecutionException; @Override @@ -132,7 +138,22 @@ private List collectFiles(FormatterFactory formatterFactory) throws MojoEx String excludesString = String.join(",", excludes); try { - return FileUtils.getFiles(baseDir, includesString, excludesString); + final List files = FileUtils.getFiles(baseDir, includesString, excludesString); + if (filePatterns == null || filePatterns.isEmpty()) { + return files; + } + final String[] includePatterns = this.filePatterns.split(","); + final List compiledIncludePatterns = Arrays.stream(includePatterns) + .map(Pattern::compile) + .collect(Collectors.toList()); + final Predicate shouldInclude = file -> compiledIncludePatterns + .stream() + .anyMatch(filePattern -> filePattern.matcher(file.getAbsolutePath()) + .matches()); + return files + .stream() + .filter(shouldInclude) + .collect(toList()); } catch (IOException e) { throw new MojoExecutionException("Unable to scan file tree rooted at " + baseDir, e); } diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/FileLocator.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/FileLocator.java index 0d28c68ee1..126ac4d49e 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/FileLocator.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/FileLocator.java @@ -46,7 +46,7 @@ public File locateFile(String path) { } catch (ResourceNotFoundException e) { throw new RuntimeException("Unable to locate file with path: " + path, e); } catch (FileResourceCreationException e) { - throw new RuntimeException("Unable to create temporaty file '" + outputFile + "' in the output directory", e); + throw new RuntimeException("Unable to create temporary file '" + outputFile + "' in the output directory", e); } } diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/SpecificFilesTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/SpecificFilesTest.java new file mode 100644 index 0000000000..8f1b739ad4 --- /dev/null +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/SpecificFilesTest.java @@ -0,0 +1,78 @@ +/* + * Copyright 2016 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.IOException; + +import org.junit.Test; + +public class SpecificFilesTest extends MavenIntegrationTest { + private String testFile(int number, boolean absolute) throws IOException { + String rel = "src/main/java/test" + number + ".java"; + if (absolute) { + return rootFolder() + "/" + rel; + } else { + return rel; + } + } + + private String testFile(int number) throws IOException { + return testFile(number, false); + } + + private String fixture(boolean formatted) { + return "java/googlejavaformat/JavaCode" + (formatted ? "F" : "Unf") + "ormatted.test"; + } + + private void integration(String patterns, boolean firstFormatted, boolean secondFormatted, boolean thirdFormatted) + throws IOException, InterruptedException { + + writePomWithJavaSteps( + "", + " src/**/java/**/*.java", + "", + "", + " 1.2", + ""); + + setFile(testFile(1)).toResource(fixture(false)); + setFile(testFile(2)).toResource(fixture(false)); + setFile(testFile(3)).toResource(fixture(false)); + + mavenRunner() + .withArguments("spotless:apply", "-DspotlessFiles=" + patterns) + .runNoError(); + + assertFile(testFile(1)).sameAsResource(fixture(firstFormatted)); + assertFile(testFile(2)).sameAsResource(fixture(secondFormatted)); + assertFile(testFile(3)).sameAsResource(fixture(thirdFormatted)); + } + + @Test + public void singleFile() throws IOException, InterruptedException { + integration(testFile(2, true), false, true, false); + } + + @Test + public void multiFile() throws IOException, InterruptedException { + integration(testFile(1, true) + "," + testFile(3, true), true, false, true); + } + + @Test + public void regexp() throws IOException, InterruptedException { + integration(".*/src/main/java/test\\(1\\|3\\).java", true, false, true); + } +}