Skip to content

Commit 249d3ca

Browse files
authored
Merge pull request #322 from vmdominguez/specify-files
allow "spotlessFiles" project property in gradle plugin to only target specific files
2 parents d57e26d + fecc1f8 commit 249d3ca

File tree

5 files changed

+157
-20
lines changed

5 files changed

+157
-20
lines changed

plugin-gradle/CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
### Version 3.17.0-SNAPSHOT - TBD ([javadoc](https://diffplug.github.io/spotless/javadoc/snapshot/), [snapshot](https://oss.sonatype.org/content/repositories/snapshots/com/diffplug/spotless/spotless-plugin-gradle/))
44

55
* Updated default eclipse-jdt from 4.7.3a to 4.9.0 ([#316](https://github.com/diffplug/spotless/pull/316)). New version addresses enum-tab formatting bug in 4.8 ([#314](https://github.com/diffplug/spotless/issues/314)).
6+
* Added `-spotlessFiles` switch to allow targeting specific files ([#322](https://github.com/diffplug/spotless/pull/322))
67

78
### Version 3.16.0 - October 30th 2018 ([javadoc](https://diffplug.github.io/spotless/javadoc/spotless-plugin-gradle/3.16.0/), [jcenter](https://bintray.com/diffplug/opensource/spotless-plugin-gradle/3.16.0))
89

plugin-gradle/README.md

+10
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,16 @@ Note that `enforceCheck` is a global property which affects all formats (outside
659659

660660
<a name="examples"></a>
661661

662+
## Can I apply Spotless to specific files?
663+
664+
You can target specific files by setting the `spotlessFiles` project property to a comma-separated list of file patterns:
665+
666+
```
667+
cmd> gradlew spotlessApply -PspotlessFiles=my/file/pattern.java,more/generic/.*-pattern.java
668+
```
669+
670+
The patterns are matched using `String#matches(String)` against the absolute file path.
671+
662672
## Example configurations (from real-world projects)
663673

664674
Spotless is hosted on jcenter and at plugins.gradle.org. [Go here](https://plugins.gradle.org/plugin/com.diffplug.gradle.spotless) if you're not sure how to import the plugin.

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

+9
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public class SpotlessPlugin implements Plugin<Project> {
3737
private static final String TASK_GROUP = "Verification";
3838
private static final String CHECK_DESCRIPTION = "Checks that sourcecode satisfies formatting steps.";
3939
private static final String APPLY_DESCRIPTION = "Applies code formatting steps to sourcecode in-place.";
40+
private static final String FILES_PROPERTY = "spotlessFiles";
4041

4142
@Override
4243
public void apply(Project project) {
@@ -63,12 +64,20 @@ void createTasks(Project project) {
6364
Task rootApplyTask = project.task(EXTENSION + APPLY);
6465
rootApplyTask.setGroup(TASK_GROUP);
6566
rootApplyTask.setDescription(APPLY_DESCRIPTION);
67+
String filePatterns;
68+
if (project.hasProperty(FILES_PROPERTY) && project.property(FILES_PROPERTY) instanceof String) {
69+
filePatterns = (String) project.property(FILES_PROPERTY);
70+
} else {
71+
// needs to be non-null since it is an @Input property of the task
72+
filePatterns = "";
73+
}
6674

6775
spotlessExtension.formats.forEach((key, value) -> {
6876
// create the task that does the work
6977
String taskName = EXTENSION + capitalize(key);
7078
SpotlessTask spotlessTask = project.getTasks().create(taskName, SpotlessTask.class);
7179
value.setupTask(spotlessTask);
80+
spotlessTask.setFilePatterns(filePatterns);
7281

7382
// create the check and apply control tasks
7483
Task checkTask = project.getTasks().create(taskName + CHECK);

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

+55-20
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,14 @@
2323
import java.nio.file.Files;
2424
import java.nio.file.StandardOpenOption;
2525
import java.util.ArrayList;
26+
import java.util.Arrays;
2627
import java.util.Collections;
2728
import java.util.List;
2829
import java.util.Locale;
2930
import java.util.Objects;
31+
import java.util.function.Predicate;
32+
import java.util.regex.Pattern;
33+
import java.util.stream.Collectors;
3034

3135
import org.gradle.api.DefaultTask;
3236
import org.gradle.api.GradleException;
@@ -82,6 +86,17 @@ public void setPaddedCell(boolean paddedCell) {
8286
this.paddedCell = paddedCell;
8387
}
8488

89+
protected String filePatterns = "";
90+
91+
@Input
92+
public String getFilePatterns() {
93+
return filePatterns;
94+
}
95+
96+
public void setFilePatterns(String filePatterns) {
97+
this.filePatterns = Objects.requireNonNull(filePatterns);
98+
}
99+
85100
protected FormatExceptionPolicy exceptionPolicy = new FormatExceptionPolicyStrict();
86101

87102
public void setExceptionPolicy(FormatExceptionPolicy exceptionPolicy) {
@@ -160,6 +175,46 @@ public void performAction(IncrementalTaskInputs inputs) throws Exception {
160175
throw new GradleException("Don't call " + getName() + " directly, call " + getName() + SpotlessPlugin.CHECK + " or " + getName() + SpotlessPlugin.APPLY);
161176
}
162177

178+
Predicate<File> shouldInclude;
179+
if (this.filePatterns.isEmpty()) {
180+
shouldInclude = file -> true;
181+
} else {
182+
// a list of files has been passed in via project property
183+
final String[] includePatterns = this.filePatterns.split(",");
184+
final List<Pattern> compiledIncludePatterns = Arrays.stream(includePatterns)
185+
.map(Pattern::compile)
186+
.collect(Collectors.toList());
187+
shouldInclude = file -> compiledIncludePatterns
188+
.stream()
189+
.anyMatch(filePattern -> filePattern.matcher(file.getAbsolutePath())
190+
.matches());
191+
}
192+
// find the outOfDate files
193+
List<File> outOfDate = new ArrayList<>();
194+
inputs.outOfDate(inputDetails -> {
195+
File file = inputDetails.getFile();
196+
if (shouldInclude.test(file) && file.isFile() && !file.equals(getCacheFile())) {
197+
outOfDate.add(file);
198+
}
199+
});
200+
// load the files that were changed by the last run
201+
// because it's possible the user changed them back to their
202+
// unformatted form, so we need to treat them as dirty
203+
// (see bug #144)
204+
if (getCacheFile().exists()) {
205+
LastApply lastApply = SerializableMisc.fromFile(LastApply.class, getCacheFile());
206+
for (File file : lastApply.changedFiles) {
207+
if (shouldInclude.test(file) && !outOfDate.contains(file) && file.exists() && Iterables.contains(target, file)) {
208+
outOfDate.add(file);
209+
}
210+
}
211+
}
212+
213+
if (outOfDate.isEmpty()) {
214+
// no work to do
215+
return;
216+
}
217+
163218
// create the formatter
164219
try (Formatter formatter = Formatter.builder()
165220
.lineEndingsPolicy(lineEndingsPolicy)
@@ -168,26 +223,6 @@ public void performAction(IncrementalTaskInputs inputs) throws Exception {
168223
.steps(steps)
169224
.exceptionPolicy(exceptionPolicy)
170225
.build()) {
171-
// find the outOfDate files
172-
List<File> outOfDate = new ArrayList<>();
173-
inputs.outOfDate(inputDetails -> {
174-
File file = inputDetails.getFile();
175-
if (file.isFile() && !file.equals(getCacheFile())) {
176-
outOfDate.add(file);
177-
}
178-
});
179-
// load the files that were changed by the last run
180-
// because it's possible the user changed them back to their
181-
// unformatted form, so we need to treat them as dirty
182-
// (see bug #144)
183-
if (getCacheFile().exists()) {
184-
LastApply lastApply = SerializableMisc.fromFile(LastApply.class, getCacheFile());
185-
for (File file : lastApply.changedFiles) {
186-
if (!outOfDate.contains(file) && file.exists() && Iterables.contains(target, file)) {
187-
outOfDate.add(file);
188-
}
189-
}
190-
}
191226

192227
if (apply) {
193228
List<File> changedFiles = applyAnyChanged(formatter, outOfDate);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Copyright 2016 DiffPlug
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.diffplug.gradle.spotless;
17+
18+
import java.io.IOException;
19+
20+
import org.junit.Test;
21+
22+
public class SpecificFilesTest extends GradleIntegrationTest {
23+
private String testFile(int number, boolean absolute) throws IOException {
24+
String rel = "src/main/java/test" + number + ".java";
25+
if (absolute) {
26+
return rootFolder() + "/" + rel;
27+
} else {
28+
return rel;
29+
}
30+
}
31+
32+
private String testFile(int number) throws IOException {
33+
return testFile(number, false);
34+
}
35+
36+
private String fixture(boolean formatted) {
37+
return "java/googlejavaformat/JavaCode" + (formatted ? "F" : "Unf") + "ormatted.test";
38+
}
39+
40+
private void integration(String patterns, boolean firstFormatted, boolean secondFormatted, boolean thirdFormatted)
41+
throws IOException {
42+
43+
setFile("build.gradle").toLines(
44+
"buildscript { repositories { mavenCentral() } }",
45+
"plugins {",
46+
" id 'com.diffplug.gradle.spotless'",
47+
"}",
48+
"apply plugin: 'java'",
49+
"spotless {",
50+
" java {",
51+
" googleJavaFormat('1.2')",
52+
" }",
53+
"}");
54+
55+
setFile(testFile(1)).toResource(fixture(false));
56+
setFile(testFile(2)).toResource(fixture(false));
57+
setFile(testFile(3)).toResource(fixture(false));
58+
59+
gradleRunner()
60+
.withArguments("spotlessApply", "-PspotlessFiles=" + patterns)
61+
.build();
62+
63+
assertFile(testFile(1)).sameAsResource(fixture(firstFormatted));
64+
assertFile(testFile(2)).sameAsResource(fixture(secondFormatted));
65+
assertFile(testFile(3)).sameAsResource(fixture(thirdFormatted));
66+
}
67+
68+
@Test
69+
public void singleFile() throws IOException {
70+
integration(testFile(2, true), false, true, false);
71+
}
72+
73+
@Test
74+
public void multiFile() throws IOException {
75+
integration(testFile(1, true) + "," + testFile(3, true), true, false, true);
76+
}
77+
78+
@Test
79+
public void regexp() throws IOException {
80+
integration(".*/src/main/java/test(1|3).java", true, false, true);
81+
}
82+
}

0 commit comments

Comments
 (0)