diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 11e9f04fc3..ffaaa932dc 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -4,6 +4,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Fixed +* Full no-asterisk support for configuration cache ([#2088](https://github.com/diffplug/spotless/pull/2088) closes [#1274](https://github.com/diffplug/spotless/issues/1274) and [#987](https://github.com/diffplug/spotless/issues/987)). * Ignore system git config when running tests ([#1990](https://github.com/diffplug/spotless/issues/1990)) * Correctly provide EditorConfig property types for Ktlint ([#2052](https://github.com/diffplug/spotless/issues/2052)) * Fixed memory leak introduced in 6.21.0 ([#2067](https://github.com/diffplug/spotless/issues/2067)) diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JvmLocalCache.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JvmLocalCache.java deleted file mode 100644 index bcc480b7c6..0000000000 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JvmLocalCache.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2021-2022 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.File; -import java.io.Serializable; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -import org.gradle.api.GradleException; -import org.gradle.api.Task; - -import com.diffplug.spotless.FileSignature; -import com.diffplug.spotless.LazyForwardingEquality; - -class JvmLocalCache { - private static GradleException cacheIsStale() { - return new GradleException("Spotless JVM-local cache is stale. Regenerate the cache with\n" + - " " + (FileSignature.machineIsWin() ? "rmdir /q /s" : "rm -rf") + " .gradle/configuration-cache\n" + - "To make this workaround obsolete, please upvote https://github.com/diffplug/spotless/issues/987"); - } - - interface LiveCache { - T get(); - - void set(T value); - } - - static LiveCache createLive(Task task, String propertyName) { - return new LiveCacheKeyImpl(new InternalCacheKey(task.getProject().getProjectDir(), task.getPath(), propertyName)); - } - - static class LiveCacheKeyImpl implements LiveCache, Serializable { - InternalCacheKey internalKey; - - LiveCacheKeyImpl(InternalCacheKey internalKey) { - this.internalKey = internalKey; - } - - @Override - public void set(T value) { - - // whenever we cache an instance of LazyForwardingEquality, we want to make sure that we give it - // a chance to null-out its initialization lambda (see https://github.com/diffplug/spotless/issues/1194#issuecomment-1120744842) - LazyForwardingEquality.unlazy(value); - daemonState.put(internalKey, value); - } - - @Override - public T get() { - Object value = daemonState.get(internalKey); - if (value == null) { - // TODO: throw TriggerConfigurationException(); (see https://github.com/diffplug/spotless/issues/987) - throw cacheIsStale(); - } else { - return (T) value; - } - } - } - - private static Map daemonState = Collections.synchronizedMap(new HashMap<>()); - - private static class InternalCacheKey implements Serializable { - private File projectDir; - private String taskPath; - private String propertyName; - - InternalCacheKey(File projectDir, String taskPath, String keyName) { - this.projectDir = projectDir; - this.taskPath = taskPath; - this.propertyName = keyName; - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - InternalCacheKey that = (InternalCacheKey) o; - return projectDir.equals(that.projectDir) && taskPath.equals(that.taskPath) && propertyName.equals(that.propertyName); - } - - @Override - public int hashCode() { - return Objects.hash(projectDir, taskPath, propertyName); - } - } -} 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 7fee3d950e..276bdadcfd 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 @@ -64,6 +64,9 @@ public LineEnding getLineEndings() { } public void setLineEndings(LineEnding lineEndings) { + if (lineEndings == LineEnding.GIT_ATTRIBUTES) { + throw new IllegalArgumentException("GIT_ATTRIBUTES not supported in Gradle, use GIT_ATTRIBUTES_FAST_ALLSAME instead. See https://github.com/diffplug/spotless/issues/1274 for more details."); + } this.lineEndings = requireNonNull(lineEndings); } 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 7b225eacd0..f930685baf 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 @@ -1,5 +1,5 @@ /* - * Copyright 2020-2023 DiffPlug + * Copyright 2020-2024 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,7 +37,6 @@ import org.gradle.api.tasks.PathSensitivity; import org.gradle.work.Incremental; -import com.diffplug.gradle.spotless.JvmLocalCache.LiveCache; import com.diffplug.spotless.FormatExceptionPolicy; import com.diffplug.spotless.FormatExceptionPolicyStrict; import com.diffplug.spotless.Formatter; @@ -49,10 +48,6 @@ public abstract class SpotlessTask extends DefaultTask { @Internal abstract Property getTaskService(); - protected LiveCache createLive(String keyName) { - return JvmLocalCache.createLive(this, keyName); - } - // set by SpotlessExtension, but possibly overridden by FormatExtension protected String encoding = "UTF-8"; @@ -65,15 +60,15 @@ public void setEncoding(String encoding) { this.encoding = Objects.requireNonNull(encoding); } - protected final LiveCache> lineEndingsPolicy = createLive("lineEndingsPolicy"); + protected Provider lineEndingsPolicy = null; @Input public Provider getLineEndingsPolicy() { - return lineEndingsPolicy.get(); + return lineEndingsPolicy; } public void setLineEndingsPolicy(Provider lineEndingsPolicy) { - this.lineEndingsPolicy.set(lineEndingsPolicy); + this.lineEndingsPolicy = lineEndingsPolicy; } /** The sha of the tree at repository root, used for determining if an individual *file* is clean according to git. */ @@ -155,22 +150,17 @@ public File getOutputDirectory() { return outputDirectory; } - protected final LiveCache> steps = createLive("steps"); - { - steps.set(new ArrayList()); - } + protected final List steps = new ArrayList<>(); @Input public List getSteps() { - return Collections.unmodifiableList(steps.get()); + return Collections.unmodifiableList(steps); } public void setSteps(List steps) { - this.steps.set(PluginGradlePreconditions.requireElementsNonNull(steps)); - } - - public boolean addStep(FormatterStep step) { - return this.steps.get().add(Objects.requireNonNull(step)); + PluginGradlePreconditions.requireElementsNonNull(steps); + this.steps.clear(); + this.steps.addAll(steps); } /** Returns the name of this format. */ @@ -186,10 +176,10 @@ String formatName() { Formatter buildFormatter() { return Formatter.builder() .name(formatName()) - .lineEndingsPolicy(lineEndingsPolicy.get().get()) + .lineEndingsPolicy(getLineEndingsPolicy().get()) .encoding(Charset.forName(encoding)) .rootDir(getProjectDir().get().getAsFile().toPath()) - .steps(steps.get()) + .steps(steps) .exceptionPolicy(exceptionPolicy) .build(); } diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/BiomeIntegrationTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/BiomeIntegrationTest.java index db4ca4b027..ba39af1705 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/BiomeIntegrationTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/BiomeIntegrationTest.java @@ -310,7 +310,7 @@ void failureWhenExeNotFound() throws Exception { var spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").buildAndFail(); assertThat(spotlessApply.getOutput()).contains("Build failed with an exception"); assertFile("biome_test.js").sameAsResource("biome/js/fileBefore.js"); - assertThat(spotlessApply.getOutput()).contains("Could not create task ':spotlessMybiomeApply'"); + assertThat(spotlessApply.getOutput()).contains("Execution failed for task ':spotlessMybiome'"); assertThat(spotlessApply.getOutput()).contains("Biome executable does not exist"); } diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/ConfigurationCacheTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/ConfigurationCacheTest.java index 70be5adb82..0306f087ac 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/ConfigurationCacheTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/ConfigurationCacheTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2023 DiffPlug + * Copyright 2020-2024 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,11 +17,8 @@ import java.io.IOException; -import org.gradle.testkit.runner.BuildResult; import org.gradle.testkit.runner.GradleRunner; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledForJreRange; -import org.junit.jupiter.api.condition.JRE; public class ConfigurationCacheTest extends GradleIntegrationHarness { @Override @@ -65,8 +62,7 @@ public void helpConfiguresIfTasksAreCreated() throws IOException { } @Test - @EnabledForJreRange(max = JRE.JAVA_20) - public void jvmLocalCache() throws IOException { + public void multipleRuns() throws IOException { setFile("build.gradle").toLines( "plugins {", " id 'com.diffplug.spotless'", @@ -93,14 +89,5 @@ public void jvmLocalCache() throws IOException { gradleRunner().withArguments("spotlessCheck").buildAndFail(); gradleRunner().withArguments("spotlessApply").build(); assertFile("test.java").sameAsResource("java/googlejavaformat/JavaCodeFormatted.test"); - - // the withDebug forces it to start a new deamon, but only in Gradle 8.3 and older - // starting with Gradle 8.5 this doesn't work anymore - // and we need Gradle 8.5 for Java 21 - // so we can't test this on Java 21 for now - BuildResult failure = gradleRunner().withDebug(true).withArguments("spotlessApply", "--stacktrace").buildAndFail(); - failure.getOutput().contains("Spotless daemon-local cache is stale. Regenerate the cache with\n" + - " rm -rf .gradle/configuration-cache\n" + - "For more information see #123\n"); } } 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 bc556ac06e..af724ab961 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 @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 DiffPlug + * Copyright 2016-2024 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -151,10 +151,10 @@ void customRunToFixMessage() throws Exception { @Test void whitespaceProblem() throws Exception { Bundle spotless = create(setFile("testFile").toContent("A \nB\t\nC \n")); - spotless.task.addStep(FormatterStep.createNeverUpToDate("trimTrailing", input -> { + spotless.task.setSteps(List.of(FormatterStep.createNeverUpToDate("trimTrailing", input -> { Pattern pattern = Pattern.compile("[ \t]+$", Pattern.UNIX_LINES | Pattern.MULTILINE); return pattern.matcher(input).replaceAll(""); - })); + }))); assertCheckFailure(spotless, " testFile", " @@ -1,3 +1,3 @@", diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/FormatTaskTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/FormatTaskTest.java index ddd813468d..92f6818f3e 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/FormatTaskTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/FormatTaskTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 DiffPlug + * Copyright 2016-2024 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ import java.io.File; import java.util.Collections; +import java.util.List; import org.gradle.api.Project; import org.gradle.api.services.BuildServiceParameters; @@ -61,7 +62,7 @@ void testStep() throws Exception { File outputFile = new File(spotlessTask.getOutputDirectory(), "testFile"); spotlessTask.setTarget(Collections.singleton(testFile)); - spotlessTask.addStep(FormatterStep.createNeverUpToDate("double-p", content -> content.replace("pp", "p"))); + spotlessTask.setSteps(List.of(FormatterStep.createNeverUpToDate("double-p", content -> content.replace("pp", "p")))); Tasks.execute(spotlessTask); assertFile(outputFile).hasContent("aple"); 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 4fe78d884d..7dc5581f5b 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 @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 DiffPlug + * Copyright 2016-2024 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import java.io.IOException; import java.util.Arrays; import java.util.Collections; +import java.util.List; import org.gradle.api.Project; import org.gradle.api.provider.Provider; @@ -65,7 +66,7 @@ public BuildServiceParameters.None getParameters() { private SpotlessTaskImpl createFormatTask(String name, FormatterStep step) { SpotlessTaskImpl task = project.getTasks().create("spotless" + SpotlessPlugin.capitalize(name), SpotlessTaskImpl.class); task.init(taskService); - task.addStep(step); + task.setSteps(List.of(step)); task.setLineEndingsPolicy(project.provider(LineEnding.UNIX::createPolicy)); task.setTarget(Collections.singletonList(file)); return task; diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/RomeIntegrationTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/RomeIntegrationTest.java index 0c12f9f500..e9f33f64ac 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/RomeIntegrationTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/RomeIntegrationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 DiffPlug + * Copyright 2023-2024 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -310,7 +310,7 @@ void failureWhenExeNotFound() throws Exception { var spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").buildAndFail(); assertThat(spotlessApply.getOutput()).contains("Build failed with an exception"); assertFile("rome_test.js").sameAsResource("rome/js/fileBefore.js"); - assertThat(spotlessApply.getOutput()).contains("Could not create task ':spotlessMyromeApply'"); + assertThat(spotlessApply.getOutput()).contains("Execution failed for task ':spotlessMyrome'"); assertThat(spotlessApply.getOutput()).contains("Biome executable does not exist"); }