diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 5727e65819..88b3ba050f 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -3,7 +3,10 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `3.27.0`). ## [Unreleased] -* Support for ktfmt in KotlinGradleExtension ([#583](https://github.com/diffplug/spotless/pull/583)) +### Added +* Support for ktfmt in KotlinGradleExtension. ([#583](https://github.com/diffplug/spotless/pull/583)) +### Fixed +* Users can now run `spotlessCheck` and `spotlessApply` in the same build. ([#584](https://github.com/diffplug/spotless/pull/584)) ## [4.0.1] - 2020-05-21 ### Fixed diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java index 7497acab50..d54c56cc7f 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java @@ -635,7 +635,7 @@ public SpotlessApply createIndependentApplyTask(String taskName) { // create the apply task SpotlessApply applyTask = root.project.getTasks().create(taskName, SpotlessApply.class); applyTask.setSpotlessOutDirectory(spotlessTask.getOutputDirectory()); - applyTask.source = spotlessTask; + applyTask.linkSource(spotlessTask); applyTask.dependsOn(spotlessTask); return applyTask; diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessApply.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessApply.java index 9d20f29fa9..7261fe788a 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessApply.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessApply.java @@ -30,7 +30,14 @@ import org.gradle.api.tasks.TaskAction; public class SpotlessApply extends DefaultTask { - SpotlessTask source; + private SpotlessTask source; + + /** Bidirectional link between Apply and Spotless allows check to know if Apply ran or not. */ + void linkSource(SpotlessTask source) { + this.source = source; + source.applyTask = this; + } + private File spotlessOutDirectory; @PathSensitive(PathSensitivity.RELATIVE) diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessCheck.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessCheck.java index 0eda5ea7d0..40d93bb47b 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessCheck.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessCheck.java @@ -49,11 +49,22 @@ public void setSpotlessOutDirectory(File spotlessOutDirectory) { this.spotlessOutDirectory = spotlessOutDirectory; } + public void performActionTest() throws Exception { + performAction(true); + } + @TaskAction public void performAction() throws Exception { + performAction(false); + } + + private void performAction(boolean isTest) { ConfigurableFileTree files = getProject().fileTree(spotlessOutDirectory); if (files.isEmpty()) { getState().setDidWork(source.getDidWork()); + } else if (!isTest && getProject().getGradle().getTaskGraph().hasTask(source.applyTask)) { + // if our matching apply has already run, then we don't need to do anything + getState().setDidWork(false); } else { List problemFiles = new ArrayList<>(); files.visit(new FileVisitor() { diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtension.java index 1ae988205f..dd7977aebe 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtension.java @@ -249,7 +249,6 @@ private T maybeCreate(String name, Class clazz) { * - "spotless{FormatName}Check" will depend on the main spotless task in `check` mode * - "spotless{FormatName}Apply" will depend on the main spotless task in `apply` mode */ - @SuppressWarnings("rawtypes") private void createFormatTasks(String name, FormatExtension formatExtension) { // create the SpotlessTask String taskName = EXTENSION + SpotlessPlugin.capitalize(name); @@ -268,9 +267,12 @@ private void createFormatTasks(String name, FormatExtension formatExtension) { SpotlessApply applyTask = project.getTasks().create(taskName + APPLY, SpotlessApply.class); applyTask.setSpotlessOutDirectory(spotlessTask.getOutputDirectory()); - applyTask.source = spotlessTask; + applyTask.linkSource(spotlessTask); applyTask.dependsOn(spotlessTask); + // if the user runs both, make sure that apply happens first, + checkTask.mustRunAfter(applyTask); + // set the filePatterns property project.afterEvaluate(unused -> { String filePatterns; diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessTask.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessTask.java index 7cc0bfccb0..bc2b23146a 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessTask.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessTask.java @@ -53,6 +53,15 @@ @CacheableTask public class SpotlessTask extends DefaultTask { + SpotlessApply applyTask; + + /** @deprecated internal use only, allows coordination between check and apply when they are in the same build */ + @Internal + @Deprecated + public SpotlessApply getApplyTask() { + return applyTask; + } + // set by SpotlessExtension, but possibly overridden by FormatExtension protected String encoding = "UTF-8"; diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/DiffMessageFormatterTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/DiffMessageFormatterTest.java index 42ad2ea239..f319f0efe9 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/DiffMessageFormatterTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/DiffMessageFormatterTest.java @@ -39,21 +39,16 @@ public class DiffMessageFormatterTest extends ResourceHarness { private class Bundle { - String name; Project project = TestProvisioner.gradleProject(rootFolder()); File file; - File outputFile; SpotlessTask task; SpotlessCheck check; - SpotlessApply apply; Bundle(String name) throws IOException { - this.name = name; file = setFile("src/test." + name).toContent("CCC"); task = createFormatTask(name); check = createCheckTask(name, task); - apply = createApplyTask(name, task); - outputFile = new File(task.getOutputDirectory() + "/src", file.getName()); + createApplyTask(name, task); } private SpotlessTask createFormatTask(String name) { @@ -72,7 +67,7 @@ private SpotlessCheck createCheckTask(String name, SpotlessTask source) { private SpotlessApply createApplyTask(String name, SpotlessTask source) { SpotlessApply task = project.getTasks().create("spotless" + SpotlessPlugin.capitalize(name) + "Apply", SpotlessApply.class); - task.source = source; + task.linkSource(this.task); task.setSpotlessOutDirectory(source.getOutputDirectory()); return task; } @@ -86,24 +81,9 @@ String checkFailureMsg() { } } - void diagnose() throws IOException { - SpotlessDiagnoseTask diagnose = project.getTasks().create("spotless" + SpotlessPlugin.capitalize(name) + "Diagnose", SpotlessDiagnoseTask.class); - diagnose.source = task; - diagnose.performAction(); - } - - void format() throws Exception { - execute(task); - } - - void apply() throws Exception { - execute(task); - apply.performAction(); - } - void check() throws Exception { execute(task); - check.performAction(); + check.performActionTest(); } } diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/PaddedCellTaskTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/PaddedCellTaskTest.java index ce068a10e2..8e4c1a20a2 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/PaddedCellTaskTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/PaddedCellTaskTest.java @@ -76,7 +76,7 @@ private SpotlessCheck createCheckTask(String name, SpotlessTask source) { private SpotlessApply createApplyTask(String name, SpotlessTask source) { SpotlessApply task = project.getTasks().create("spotless" + SpotlessPlugin.capitalize(name) + "Apply", SpotlessApply.class); - task.source = source; + task.linkSource(source); task.setSpotlessOutDirectory(source.getOutputDirectory()); return task; } @@ -107,7 +107,7 @@ void apply() throws Exception { void check() throws Exception { execute(task); - check.performAction(); + check.performActionTest(); } } diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpecificFilesTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpecificFilesTest.java index 347546332c..452cd9b22e 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpecificFilesTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/SpecificFilesTest.java @@ -16,23 +16,38 @@ package com.diffplug.gradle.spotless; import java.io.IOException; +import java.util.Locale; -import org.gradle.testkit.runner.*; +import org.gradle.testkit.runner.GradleRunner; +import org.gradle.testkit.runner.UnexpectedBuildFailure; import org.junit.Ignore; import org.junit.Test; +import com.diffplug.common.base.StandardSystemProperty; + public class SpecificFilesTest extends GradleIntegrationTest { + private static boolean isWindows() { + return StandardSystemProperty.OS_NAME.value().toLowerCase(Locale.US).contains("win"); + } + + private static String regexWinSafe(String input) { + return isWindows() ? input.replace("/", "\\\\") : input; + } + private String testFilePath(int number) { return testFilePath(number, true); } private String testFilePath(int number, boolean absolute) { String relPath = "src/main/java/test" + number + ".java"; + String returnValue; if (absolute) { - return rootFolder() + "/" + relPath; + returnValue = rootFolder().getAbsolutePath().replace('\\', '/') + "/" + relPath; } else { - return relPath; + returnValue = relPath; } + // regex-escape on windows; + return regexWinSafe(returnValue); } private String fixture() { @@ -141,7 +156,7 @@ public void matchesNoFiles_formatsNoFilesButDoesNotExitInError() throws IOExcept @Test public void regexp() throws IOException { createBuildScript(); - integration(".*/src/main/java/test(1|3).java", true, false, true); + integration(regexWinSafe(".*/src/main/java/test(1|3).java"), true, false, true); } @Test(expected = UnexpectedBuildFailure.class) diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/UpToDateTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/UpToDateTest.java index a370bfd1ad..53657985ee 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/UpToDateTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/UpToDateTest.java @@ -98,4 +98,11 @@ public void testPathologicalCase() throws IOException { applyIsUpToDate(false); applyIsUpToDate(true); } + + @Test + public void checkAndApply() throws IOException { + writeBuildFile(); + setFile("README.md").toContent("ABC"); + gradleRunner().withArguments("spotlessCheck", "spotlessApply").build(); + } }