Skip to content

Commit 0b0b5de

Browse files
Make SpotlessDiagnoseTask compatible with the configuration cache
1 parent b8e8f48 commit 0b0b5de

File tree

8 files changed

+142
-58
lines changed

8 files changed

+142
-58
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright 2025 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.nio.charset.Charset;
19+
20+
import org.gradle.api.model.ObjectFactory;
21+
import org.gradle.api.provider.Property;
22+
import org.gradle.api.tasks.Input;
23+
import org.gradle.api.tasks.Internal;
24+
25+
import com.diffplug.spotless.ConfigurationCacheHackList;
26+
import com.diffplug.spotless.Formatter;
27+
import com.diffplug.spotless.LineEnding;
28+
29+
final class FormatterSpec {
30+
31+
private final Property<String> encoding;
32+
33+
@Input
34+
Property<String> getEncoding() {
35+
return encoding;
36+
}
37+
38+
private final Property<LineEnding.Policy> lineEndingsPolicy;
39+
40+
@Input
41+
Property<LineEnding.Policy> getLineEndingsPolicy() {
42+
return lineEndingsPolicy;
43+
}
44+
45+
private final ConfigurationCacheHackList stepsInternalRoundtrip = ConfigurationCacheHackList.forRoundtrip();
46+
47+
@Internal
48+
public ConfigurationCacheHackList getStepsInternalRoundtrip() {
49+
return stepsInternalRoundtrip;
50+
}
51+
52+
FormatterSpec(ObjectFactory objects) {
53+
encoding = objects.property(String.class);
54+
lineEndingsPolicy = objects.property(LineEnding.Policy.class);
55+
56+
// set by SpotlessExtension, but possibly overridden by FormatExtension
57+
getEncoding().convention("UTF-8");
58+
}
59+
60+
Formatter buildFormatter() {
61+
return Formatter.builder()
62+
.lineEndingsPolicy(getLineEndingsPolicy().get())
63+
.encoding(Charset.forName(getEncoding().get()))
64+
.steps(stepsInternalRoundtrip.getSteps())
65+
.build();
66+
}
67+
68+
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2024 DiffPlug
2+
* Copyright 2016-2025 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -63,7 +63,7 @@ static void performHook(SpotlessTaskImpl spotlessTask, IdeHook.State state) {
6363
}
6464
if (spotlessTask.getTarget().contains(file)) {
6565
GitRatchetGradle ratchet = spotlessTask.getRatchet();
66-
try (Formatter formatter = spotlessTask.buildFormatter()) {
66+
try (Formatter formatter = spotlessTask.getFormatterSpec().buildFormatter()) {
6767
if (ratchet != null) {
6868
if (ratchet.isClean(spotlessTask.getProjectDir().get().getAsFile(), spotlessTask.getRootTreeSha(), file)) {
6969
dumpIsClean();

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

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,17 @@
2222
import java.nio.file.Paths;
2323
import java.util.Locale;
2424

25+
import javax.inject.Inject;
26+
2527
import org.gradle.api.DefaultTask;
26-
import org.gradle.api.tasks.Internal;
28+
import org.gradle.api.file.ConfigurableFileCollection;
29+
import org.gradle.api.file.FileSystemOperations;
30+
import org.gradle.api.file.ProjectLayout;
31+
import org.gradle.api.provider.Property;
32+
import org.gradle.api.tasks.Input;
33+
import org.gradle.api.tasks.InputFiles;
34+
import org.gradle.api.tasks.PathSensitive;
35+
import org.gradle.api.tasks.PathSensitivity;
2736
import org.gradle.api.tasks.TaskAction;
2837
import org.gradle.api.tasks.UntrackedTask;
2938

@@ -33,23 +42,39 @@
3342
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
3443

3544
@UntrackedTask(because = "undeclared inputs/outputs")
36-
public class SpotlessDiagnoseTask extends DefaultTask {
37-
SpotlessTask source;
45+
public abstract class SpotlessDiagnoseTask extends DefaultTask {
46+
47+
@Inject
48+
protected abstract ProjectLayout getProjectLayout();
49+
50+
@Inject
51+
protected abstract FileSystemOperations getFileSystemOperations();
52+
53+
@Input
54+
protected abstract Property<String> getFormatName();
55+
56+
@Input
57+
protected abstract Property<FormatterSpec> getFormatter();
58+
59+
@InputFiles
60+
@PathSensitive(PathSensitivity.RELATIVE)
61+
protected abstract ConfigurableFileCollection getTarget();
3862

39-
@Internal
40-
public SpotlessTask getSource() {
41-
return source;
63+
void init(SpotlessTask source) {
64+
getFormatName().convention(source.formatName());
65+
getFormatter().convention(source.getFormatterSpec());
66+
getTarget().setFrom(source.getTarget());
4267
}
4368

4469
@TaskAction
4570
@SuppressFBWarnings("NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE")
4671
public void performAction() throws IOException {
47-
Path srcRoot = getProject().getProjectDir().toPath();
48-
Path diagnoseRoot = getProject().getLayout().getBuildDirectory().getAsFile().get()
49-
.toPath().resolve("spotless-diagnose-" + source.formatName());
50-
getProject().delete(diagnoseRoot.toFile());
51-
try (Formatter formatter = source.buildFormatter()) {
52-
for (File file : source.target) {
72+
Path srcRoot = getProjectLayout().getProjectDirectory().getAsFile().toPath();
73+
Path diagnoseRoot = getProjectLayout().getBuildDirectory().getAsFile().get()
74+
.toPath().resolve("spotless-diagnose-" + getFormatName().get());
75+
getFileSystemOperations().delete(spec -> spec.delete(diagnoseRoot));
76+
try (Formatter formatter = getFormatter().get().buildFormatter()) {
77+
for (File file : getTarget()) {
5378
getLogger().debug("Running padded cell check on " + file);
5479
PaddedCell padded = PaddedCell.check(formatter, file);
5580
if (!padded.misbehaved()) {

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2024 DiffPlug
2+
* Copyright 2016-2025 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -96,7 +96,9 @@ protected void createFormatTasks(String name, FormatExtension formatExtension) {
9696

9797
// create the diagnose task
9898
TaskProvider<SpotlessDiagnoseTask> diagnoseTask = tasks.register(taskName + DIAGNOSE, SpotlessDiagnoseTask.class, task -> {
99-
task.source = spotlessTask.get();
99+
SpotlessTaskImpl source = spotlessTask.get();
100+
task.init(source);
101+
100102
task.setGroup(TASK_GROUP);
101103
task.mustRunAfter(BasePlugin.CLEAN_TASK_NAME);
102104
});

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

Lines changed: 22 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,30 @@
1616
package com.diffplug.gradle.spotless;
1717

1818
import java.io.File;
19-
import java.nio.charset.Charset;
2019
import java.util.ArrayList;
2120
import java.util.List;
2221
import java.util.Locale;
2322
import java.util.Objects;
2423

2524
import org.eclipse.jgit.lib.ObjectId;
2625
import org.gradle.api.DefaultTask;
26+
import org.gradle.api.file.ConfigurableFileCollection;
2727
import org.gradle.api.file.DirectoryProperty;
2828
import org.gradle.api.file.FileCollection;
2929
import org.gradle.api.provider.Property;
3030
import org.gradle.api.provider.Provider;
3131
import org.gradle.api.tasks.Input;
3232
import org.gradle.api.tasks.InputFiles;
3333
import org.gradle.api.tasks.Internal;
34+
import org.gradle.api.tasks.Nested;
3435
import org.gradle.api.tasks.OutputDirectory;
3536
import org.gradle.api.tasks.PathSensitive;
3637
import org.gradle.api.tasks.PathSensitivity;
38+
import org.gradle.api.tasks.SkipWhenEmpty;
3739
import org.gradle.work.DisableCachingByDefault;
3840
import org.gradle.work.Incremental;
3941

4042
import com.diffplug.spotless.ConfigurationCacheHackList;
41-
import com.diffplug.spotless.Formatter;
4243
import com.diffplug.spotless.FormatterStep;
4344
import com.diffplug.spotless.LineEnding;
4445
import com.diffplug.spotless.LintSuppression;
@@ -49,27 +50,29 @@ public abstract class SpotlessTask extends DefaultTask {
4950
@Internal
5051
abstract Property<SpotlessTaskService> getTaskService();
5152

52-
// set by SpotlessExtension, but possibly overridden by FormatExtension
53-
protected String encoding = "UTF-8";
53+
private final FormatterSpec formatterSpec = new FormatterSpec(getProject().getObjects());
5454

55-
@Input
55+
@Nested
56+
protected FormatterSpec getFormatterSpec() {
57+
return formatterSpec;
58+
}
59+
60+
@Internal
5661
public String getEncoding() {
57-
return encoding;
62+
return getFormatterSpec().getEncoding().get();
5863
}
5964

6065
public void setEncoding(String encoding) {
61-
this.encoding = Objects.requireNonNull(encoding);
66+
getFormatterSpec().getEncoding().set(Objects.requireNonNull(encoding));
6267
}
6368

64-
protected Provider<LineEnding.Policy> lineEndingsPolicy = null;
65-
66-
@Input
69+
@Internal
6770
public Provider<LineEnding.Policy> getLineEndingsPolicy() {
68-
return lineEndingsPolicy;
71+
return getFormatterSpec().getLineEndingsPolicy();
6972
}
7073

7174
public void setLineEndingsPolicy(Provider<LineEnding.Policy> lineEndingsPolicy) {
72-
this.lineEndingsPolicy = lineEndingsPolicy;
75+
getFormatterSpec().getLineEndingsPolicy().set(lineEndingsPolicy);
7376
}
7477

7578
/**
@@ -135,21 +138,19 @@ public List<LintSuppression> getLintSuppressions() {
135138
return lintSuppressions;
136139
}
137140

138-
protected FileCollection target;
141+
@Internal
142+
protected abstract ConfigurableFileCollection getTargetInternal();
139143

140144
@PathSensitive(PathSensitivity.RELATIVE)
141145
@Incremental
142146
@InputFiles
147+
@SkipWhenEmpty
143148
public FileCollection getTarget() {
144-
return target;
149+
return getTargetInternal();
145150
}
146151

147152
public void setTarget(Iterable<File> target) {
148-
if (target instanceof FileCollection) {
149-
this.target = (FileCollection) target;
150-
} else {
151-
this.target = getProject().files(target);
152-
}
153+
getTargetInternal().setFrom(target);
153154
}
154155

155156
protected File cleanDirectory = new File(getProject().getLayout().getBuildDirectory().getAsFile().get(),
@@ -168,24 +169,18 @@ public File getLintsDirectory() {
168169
return lintsDirectory;
169170
}
170171

171-
private final ConfigurationCacheHackList stepsInternalRoundtrip = ConfigurationCacheHackList.forRoundtrip();
172172
private final ConfigurationCacheHackList stepsInternalEquality = ConfigurationCacheHackList.forEquality();
173173

174-
@Internal
175-
public ConfigurationCacheHackList getStepsInternalRoundtrip() {
176-
return stepsInternalRoundtrip;
177-
}
178-
179174
@Input
180175
public ConfigurationCacheHackList getStepsInternalEquality() {
181176
return stepsInternalEquality;
182177
}
183178

184179
public void setSteps(List<FormatterStep> steps) {
185180
PluginGradlePreconditions.requireElementsNonNull(steps);
186-
this.stepsInternalRoundtrip.clear();
181+
this.formatterSpec.getStepsInternalRoundtrip().clear();
187182
this.stepsInternalEquality.clear();
188-
this.stepsInternalRoundtrip.addAll(steps);
183+
this.formatterSpec.getStepsInternalRoundtrip().addAll(steps);
189184
this.stepsInternalEquality.addAll(steps);
190185
}
191186

@@ -198,12 +193,4 @@ String formatName() {
198193
return name;
199194
}
200195
}
201-
202-
Formatter buildFormatter() {
203-
return Formatter.builder()
204-
.lineEndingsPolicy(getLineEndingsPolicy().get())
205-
.encoding(Charset.forName(encoding))
206-
.steps(stepsInternalRoundtrip.getSteps())
207-
.build();
208-
}
209196
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2024 DiffPlug
2+
* Copyright 2016-2025 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -84,7 +84,7 @@ public void performAction(InputChanges inputs) throws Exception {
8484

8585
SpotlessTaskService taskService = getTaskService().get();
8686
taskService.registerSourceAlreadyRan(this);
87-
if (target == null) {
87+
if (getTargetInternal().getFrom().isEmpty()) {
8888
throw new GradleException("You must specify 'Iterable<File> target'");
8989
}
9090

@@ -96,9 +96,9 @@ public void performAction(InputChanges inputs) throws Exception {
9696
Files.createDirectories(lintsDirectory.toPath());
9797
}
9898

99-
try (Formatter formatter = buildFormatter()) {
99+
try (Formatter formatter = getFormatterSpec().buildFormatter()) {
100100
GitRatchetGradle ratchet = getRatchet();
101-
for (FileChange fileChange : inputs.getFileChanges(target)) {
101+
for (FileChange fileChange : inputs.getFileChanges(getTarget())) {
102102
File input = fileChange.getFile();
103103
File projectDir = getProjectDir().get().getAsFile();
104104
String relativePath = FormatExtension.relativize(projectDir, input);

plugin-gradle/src/test/java/com/diffplug/gradle/spotless/ConfigurationCacheTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020-2024 DiffPlug
2+
* Copyright 2020-2025 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -84,10 +84,12 @@ public void multipleRuns() throws IOException {
8484
gradleRunner().withArguments("spotlessApply", "--stacktrace").build();
8585
gradleRunner().withArguments("spotlessApply").build();
8686
gradleRunner().withArguments("spotlessApply").build();
87+
gradleRunner().withArguments("spotlessDiagnose").build();
8788

8889
setFile("test.java").toResource("java/googlejavaformat/JavaCodeUnformatted.test");
8990
gradleRunner().withArguments("spotlessCheck").buildAndFail();
9091
gradleRunner().withArguments("spotlessApply").build();
92+
gradleRunner().withArguments("spotlessDiagnose").build();
9193
assertFile("test.java").sameAsResource("java/googlejavaformat/JavaCodeFormatted.test");
9294
}
9395
}

plugin-gradle/src/test/java/com/diffplug/gradle/spotless/PaddedCellTaskTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2024 DiffPlug
2+
* Copyright 2016-2025 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -96,7 +96,7 @@ String checkFailureMsg() {
9696

9797
void diagnose() throws IOException {
9898
SpotlessDiagnoseTask diagnose = project.getTasks().create("spotless" + SpotlessPlugin.capitalize(name) + "Diagnose", SpotlessDiagnoseTask.class);
99-
diagnose.source = source;
99+
diagnose.init(source);
100100
diagnose.performAction();
101101
}
102102

0 commit comments

Comments
 (0)