Skip to content

Commit

Permalink
Merge pull request #322 from vmdominguez/specify-files
Browse files Browse the repository at this point in the history
allow "spotlessFiles" project property in gradle plugin to only target specific files
  • Loading branch information
nedtwigg authored Dec 13, 2018
2 parents d57e26d + fecc1f8 commit 249d3ca
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 20 deletions.
1 change: 1 addition & 0 deletions plugin-gradle/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
### 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/))

* 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)).
* Added `-spotlessFiles` switch to allow targeting specific files ([#322](https://github.com/diffplug/spotless/pull/322))

### 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))

Expand Down
10 changes: 10 additions & 0 deletions plugin-gradle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,16 @@ Note that `enforceCheck` is a global property which affects all formats (outside

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

## 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> gradlew spotlessApply -PspotlessFiles=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)

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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public class SpotlessPlugin implements Plugin<Project> {
private static final String TASK_GROUP = "Verification";
private static final String CHECK_DESCRIPTION = "Checks that sourcecode satisfies formatting steps.";
private static final String APPLY_DESCRIPTION = "Applies code formatting steps to sourcecode in-place.";
private static final String FILES_PROPERTY = "spotlessFiles";

@Override
public void apply(Project project) {
Expand All @@ -63,12 +64,20 @@ void createTasks(Project project) {
Task rootApplyTask = project.task(EXTENSION + APPLY);
rootApplyTask.setGroup(TASK_GROUP);
rootApplyTask.setDescription(APPLY_DESCRIPTION);
String filePatterns;
if (project.hasProperty(FILES_PROPERTY) && project.property(FILES_PROPERTY) instanceof String) {
filePatterns = (String) project.property(FILES_PROPERTY);
} else {
// needs to be non-null since it is an @Input property of the task
filePatterns = "";
}

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

// create the check and apply control tasks
Task checkTask = project.getTasks().create(taskName + CHECK);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,14 @@
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.gradle.api.DefaultTask;
import org.gradle.api.GradleException;
Expand Down Expand Up @@ -82,6 +86,17 @@ public void setPaddedCell(boolean paddedCell) {
this.paddedCell = paddedCell;
}

protected String filePatterns = "";

@Input
public String getFilePatterns() {
return filePatterns;
}

public void setFilePatterns(String filePatterns) {
this.filePatterns = Objects.requireNonNull(filePatterns);
}

protected FormatExceptionPolicy exceptionPolicy = new FormatExceptionPolicyStrict();

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

Predicate<File> shouldInclude;
if (this.filePatterns.isEmpty()) {
shouldInclude = file -> true;
} else {
// a list of files has been passed in via project property
final String[] includePatterns = this.filePatterns.split(",");
final List<Pattern> compiledIncludePatterns = Arrays.stream(includePatterns)
.map(Pattern::compile)
.collect(Collectors.toList());
shouldInclude = file -> compiledIncludePatterns
.stream()
.anyMatch(filePattern -> filePattern.matcher(file.getAbsolutePath())
.matches());
}
// find the outOfDate files
List<File> outOfDate = new ArrayList<>();
inputs.outOfDate(inputDetails -> {
File file = inputDetails.getFile();
if (shouldInclude.test(file) && file.isFile() && !file.equals(getCacheFile())) {
outOfDate.add(file);
}
});
// load the files that were changed by the last run
// because it's possible the user changed them back to their
// unformatted form, so we need to treat them as dirty
// (see bug #144)
if (getCacheFile().exists()) {
LastApply lastApply = SerializableMisc.fromFile(LastApply.class, getCacheFile());
for (File file : lastApply.changedFiles) {
if (shouldInclude.test(file) && !outOfDate.contains(file) && file.exists() && Iterables.contains(target, file)) {
outOfDate.add(file);
}
}
}

if (outOfDate.isEmpty()) {
// no work to do
return;
}

// create the formatter
try (Formatter formatter = Formatter.builder()
.lineEndingsPolicy(lineEndingsPolicy)
Expand All @@ -168,26 +223,6 @@ public void performAction(IncrementalTaskInputs inputs) throws Exception {
.steps(steps)
.exceptionPolicy(exceptionPolicy)
.build()) {
// find the outOfDate files
List<File> outOfDate = new ArrayList<>();
inputs.outOfDate(inputDetails -> {
File file = inputDetails.getFile();
if (file.isFile() && !file.equals(getCacheFile())) {
outOfDate.add(file);
}
});
// load the files that were changed by the last run
// because it's possible the user changed them back to their
// unformatted form, so we need to treat them as dirty
// (see bug #144)
if (getCacheFile().exists()) {
LastApply lastApply = SerializableMisc.fromFile(LastApply.class, getCacheFile());
for (File file : lastApply.changedFiles) {
if (!outOfDate.contains(file) && file.exists() && Iterables.contains(target, file)) {
outOfDate.add(file);
}
}
}

if (apply) {
List<File> changedFiles = applyAnyChanged(formatter, outOfDate);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* 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.gradle.spotless;

import java.io.IOException;

import org.junit.Test;

public class SpecificFilesTest extends GradleIntegrationTest {
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 {

setFile("build.gradle").toLines(
"buildscript { repositories { mavenCentral() } }",
"plugins {",
" id 'com.diffplug.gradle.spotless'",
"}",
"apply plugin: 'java'",
"spotless {",
" java {",
" googleJavaFormat('1.2')",
" }",
"}");

setFile(testFile(1)).toResource(fixture(false));
setFile(testFile(2)).toResource(fixture(false));
setFile(testFile(3)).toResource(fixture(false));

gradleRunner()
.withArguments("spotlessApply", "-PspotlessFiles=" + patterns)
.build();

assertFile(testFile(1)).sameAsResource(fixture(firstFormatted));
assertFile(testFile(2)).sameAsResource(fixture(secondFormatted));
assertFile(testFile(3)).sameAsResource(fixture(thirdFormatted));
}

@Test
public void singleFile() throws IOException {
integration(testFile(2, true), false, true, false);
}

@Test
public void multiFile() throws IOException {
integration(testFile(1, true) + "," + testFile(3, true), true, false, true);
}

@Test
public void regexp() throws IOException {
integration(".*/src/main/java/test(1|3).java", true, false, true);
}
}

0 comments on commit 249d3ca

Please sign in to comment.