Skip to content

Commit 3db843d

Browse files
committed
Make non-predeclared spotless compatible with isolated projects
1 parent 368cedf commit 3db843d

File tree

11 files changed

+94
-45
lines changed

11 files changed

+94
-45
lines changed

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,11 @@ public FormatExtension(SpotlessExtension spotless) {
9494
}
9595

9696
protected final Provisioner provisioner() {
97-
return spotless.getRegisterDependenciesTask().getTaskService().get().provisionerFor(spotless);
97+
return spotless.getSpotlessTaskService().get().provisionerFor(spotless);
9898
}
9999

100100
protected final com.diffplug.spotless.extra.P2Provisioner p2Provisioner() {
101-
return spotless.getRegisterDependenciesTask().getTaskService().get().p2ProvisionerFor(spotless);
101+
return spotless.getSpotlessTaskService().get().p2ProvisionerFor(spotless);
102102
}
103103

104104
private String formatName() {
@@ -1098,7 +1098,7 @@ protected void setupTask(SpotlessTask task) {
10981098
LineEnding lineEndings = getLineEndings();
10991099
task.setLineEndingsPolicy(
11001100
getProject().provider(() -> lineEndings.createPolicy(projectDir.getAsFile(), () -> totalTarget)));
1101-
spotless.getRegisterDependenciesTask().hookSubprojectTask(task);
1101+
spotless.getSpotlessTaskService().get().hookSubprojectTask(getProject(), task);
11021102
task.setupRatchet(getRatchetFrom() != null ? getRatchetFrom() : "");
11031103
}
11041104

@@ -1134,7 +1134,7 @@ public TaskProvider<SpotlessApply> createIndependentApplyTaskLazy(String taskNam
11341134
"Task name must not end with " + SpotlessExtension.APPLY);
11351135
TaskProvider<SpotlessTaskImpl> spotlessTask = spotless.project.getTasks()
11361136
.register(taskName + SpotlessTaskService.INDEPENDENT_HELPER, SpotlessTaskImpl.class, task -> {
1137-
task.init(spotless.getRegisterDependenciesTask().getTaskService());
1137+
task.init(spotless.getSpotlessTaskService());
11381138
setupTask(task);
11391139
// clean removes the SpotlessCache, so we have to run after clean
11401140
task.mustRunAfter(BasePlugin.CLEAN_TASK_NAME);

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,7 @@ void hookSubprojectTask(SpotlessTask task) {
6464
void setup() {
6565
Preconditions.checkArgument(getProject().getRootProject() == getProject(), "Can only be used on the root project");
6666
String compositeBuildSuffix = getName().substring(TASK_NAME.length()); // see https://github.com/diffplug/spotless/pull/1001
67-
BuildServiceRegistry buildServices = getProject().getGradle().getSharedServices();
68-
taskService = buildServices.registerIfAbsent("SpotlessTaskService" + compositeBuildSuffix, SpotlessTaskService.class, spec -> {});
67+
taskService = SpotlessTaskService.registerIfAbsent(getProject(), compositeBuildSuffix);
6968
usesService(taskService);
7069
getBuildEventsListenerRegistry().onTaskCompletion(taskService);
7170
unitOutput = new File(getProject().getLayout().getBuildDirectory().getAsFile().get(), "tmp/spotless-register-dependencies");

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

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,14 @@
2727
import org.gradle.api.Action;
2828
import org.gradle.api.GradleException;
2929
import org.gradle.api.Project;
30-
import org.gradle.api.tasks.TaskContainer;
31-
import org.gradle.api.tasks.TaskProvider;
30+
import org.gradle.api.provider.Provider;
3231
import org.gradle.language.base.plugins.LifecycleBasePlugin;
3332

3433
import com.diffplug.spotless.LineEnding;
3534

3635
public abstract class SpotlessExtension {
3736
final Project project;
38-
private final RegisterDependenciesTask registerDependenciesTask;
37+
private final Provider<SpotlessTaskService> spotlessTaskService;
3938

4039
protected static final String TASK_GROUP = LifecycleBasePlugin.VERIFICATION_GROUP;
4140
protected static final String BUILD_SETUP_TASK_GROUP = "build setup";
@@ -52,11 +51,11 @@ public abstract class SpotlessExtension {
5251

5352
protected SpotlessExtension(Project project) {
5453
this.project = requireNonNull(project);
55-
this.registerDependenciesTask = findRegisterDepsTask().get();
54+
this.spotlessTaskService = SpotlessTaskService.registerIfAbsent(project, "");
5655
}
5756

58-
RegisterDependenciesTask getRegisterDependenciesTask() {
59-
return registerDependenciesTask;
57+
Provider<SpotlessTaskService> getSpotlessTaskService() {
58+
return spotlessTaskService;
6059
}
6160

6261
/** Line endings (if any). */
@@ -303,27 +302,6 @@ <T extends FormatExtension> T instantiateFormatExtension(Class<T> clazz) {
303302

304303
protected abstract void createFormatTasks(String name, FormatExtension formatExtension);
305304

306-
TaskProvider<RegisterDependenciesTask> findRegisterDepsTask() {
307-
try {
308-
return findRegisterDepsTask(RegisterDependenciesTask.TASK_NAME);
309-
} catch (Exception e) {
310-
// in a composite build there can be multiple Spotless plugins on the classpath, and they will each try to register
311-
// a task on the root project with the same name. That will generate casting errors, which we can catch and try again
312-
// with an identity-specific identifier.
313-
// https://github.com/diffplug/spotless/pull/1001 for details
314-
return findRegisterDepsTask(RegisterDependenciesTask.TASK_NAME + System.identityHashCode(RegisterDependenciesTask.class));
315-
}
316-
}
317-
318-
private TaskProvider<RegisterDependenciesTask> findRegisterDepsTask(String taskName) {
319-
TaskContainer rootProjectTasks = project.getRootProject().getTasks();
320-
if (!rootProjectTasks.getNames().contains(taskName)) {
321-
return rootProjectTasks.register(taskName, RegisterDependenciesTask.class, RegisterDependenciesTask::setup);
322-
} else {
323-
return rootProjectTasks.named(taskName, RegisterDependenciesTask.class);
324-
}
325-
}
326-
327305
public void predeclareDepsFromBuildscript() {
328306
if (project.getRootProject() != project) {
329307
throw new GradleException("predeclareDepsFromBuildscript can only be called from the root project");

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ protected void createFormatTasks(String name, FormatExtension formatExtension) {
6161
// create the SpotlessTask
6262
String taskName = EXTENSION + SpotlessPlugin.capitalize(name);
6363
TaskProvider<SpotlessTaskImpl> spotlessTask = tasks.register(taskName, SpotlessTaskImpl.class, task -> {
64-
task.init(getRegisterDependenciesTask().getTaskService());
64+
task.init(getSpotlessTaskService());
6565
task.setGroup(TASK_GROUP);
6666
task.getIdeHookState().set(ideHook);
6767
// clean removes the SpotlessCache, so we have to run after clean

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

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,29 @@
2020

2121
import org.gradle.api.Action;
2222
import org.gradle.api.Project;
23+
import org.gradle.api.tasks.TaskContainer;
24+
import org.gradle.api.tasks.TaskProvider;
2325

2426
import com.diffplug.spotless.LazyForwardingEquality;
2527

2628
public class SpotlessExtensionPredeclare extends SpotlessExtension {
2729
private final SortedMap<String, FormatExtension> toSetup = new TreeMap<>();
30+
private final RegisterDependenciesTask registerDependenciesTask;
2831

2932
public SpotlessExtensionPredeclare(Project project, GradleProvisioner.Policy policy) {
3033
super(project);
31-
getRegisterDependenciesTask().getTaskService().get().predeclaredProvisioner = policy.dedupingProvisioner(project);
32-
getRegisterDependenciesTask().getTaskService().get().predeclaredP2Provisioner = policy.dedupingP2Provisioner(project);
34+
this.registerDependenciesTask = findRegisterDepsTask().get();
35+
SpotlessTaskService taskService = getSpotlessTaskService().get();
36+
taskService.isUsingPredeclared = true;
37+
taskService.predeclaredProvisioner = policy.dedupingProvisioner(project);
38+
taskService.predeclaredP2Provisioner = policy.dedupingP2Provisioner(project);
3339
project.afterEvaluate(unused -> toSetup.forEach((name, formatExtension) -> {
3440
for (Action<FormatExtension> lazyAction : formatExtension.lazyActions) {
3541
lazyAction.execute(formatExtension);
3642
}
37-
getRegisterDependenciesTask().steps.addAll(formatExtension.steps);
43+
registerDependenciesTask.steps.addAll(formatExtension.steps);
3844
// needed to fix Deemon memory leaks (#1194), but this line came from https://github.com/diffplug/spotless/pull/1206
39-
LazyForwardingEquality.unlazy(getRegisterDependenciesTask().steps);
45+
LazyForwardingEquality.unlazy(registerDependenciesTask.steps);
4046
}));
4147
}
4248

@@ -49,4 +55,21 @@ protected void createFormatTasks(String name, FormatExtension formatExtension) {
4955
protected void predeclare(GradleProvisioner.Policy policy) {
5056
throw new UnsupportedOperationException("predeclare can't be called from within `" + EXTENSION_PREDECLARE + "`");
5157
}
58+
59+
private TaskProvider<RegisterDependenciesTask> findRegisterDepsTask() {
60+
try {
61+
return findRegisterDepsTask(RegisterDependenciesTask.TASK_NAME);
62+
} catch (Exception e) {
63+
// in a composite build there can be multiple Spotless plugins on the classpath, and they will each try to register
64+
// a task on the root project with the same name. That will generate casting errors, which we can catch and try again
65+
// with an identity-specific identifier.
66+
// https://github.com/diffplug/spotless/pull/1001 for details
67+
return findRegisterDepsTask(RegisterDependenciesTask.TASK_NAME + System.identityHashCode(RegisterDependenciesTask.class));
68+
}
69+
}
70+
71+
private TaskProvider<RegisterDependenciesTask> findRegisterDepsTask(String taskName) {
72+
return project.getTasks().register(taskName, RegisterDependenciesTask.class, RegisterDependenciesTask::setup);
73+
}
74+
5275
}

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import javax.inject.Inject;
2929

3030
import org.gradle.api.DefaultTask;
31+
import org.gradle.api.Project;
3132
import org.gradle.api.file.ConfigurableFileTree;
3233
import org.gradle.api.file.DirectoryProperty;
3334
import org.gradle.api.file.FileVisitDetails;
@@ -55,6 +56,7 @@
5556
* apply already did).
5657
*/
5758
public abstract class SpotlessTaskService implements BuildService<BuildServiceParameters.None>, AutoCloseable, OperationCompletionListener {
59+
protected boolean isUsingPredeclared = false;
5860
private final Map<String, SpotlessApply> apply = Collections.synchronizedMap(new HashMap<>());
5961
private final Map<String, SpotlessTask> source = Collections.synchronizedMap(new HashMap<>());
6062
private final Map<String, Provisioner> provisioner = Collections.synchronizedMap(new HashMap<>());
@@ -126,6 +128,20 @@ static void usesServiceTolerateTestFailure(DefaultTask task, Provider<SpotlessTa
126128
}
127129
}
128130

131+
public void hookSubprojectTask(Project project, SpotlessTask task) {
132+
// This check allows isolated projects support by not accessing the root project tasks unless really needed
133+
if (!isUsingPredeclared) return;
134+
135+
project.getRootProject().getTasks().withType(RegisterDependenciesTask.class, (registerTask) -> {
136+
registerTask.hookSubprojectTask(task);
137+
});
138+
}
139+
140+
public static Provider<SpotlessTaskService> registerIfAbsent(Project project, String suffix) {
141+
return project.getGradle().getSharedServices()
142+
.registerIfAbsent("SpotlessTaskService" + suffix, SpotlessTaskService.class, spec -> {});
143+
}
144+
129145
abstract static class ClientTask extends DefaultTask {
130146
@Internal
131147
abstract Property<File> getSpotlessCleanDirectory();

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,9 @@ private void expectSuccess() throws Exception {
136136
private StringSelfie expectFailureAndConsoleToBe() throws Exception {
137137
BuildResult result = gradleRunner().withArguments("check").buildAndFail();
138138
String output = result.getOutput();
139-
int register = output.indexOf(":spotlessInternalRegisterDependencies");
140-
int firstNewlineAfterThat = output.indexOf('\n', register + 1);
139+
int firstTask = output.indexOf("> Task");
141140
int firstTry = output.indexOf("\n* Try:");
142-
String useThisToMatch = output.substring(firstNewlineAfterThat, firstTry).trim();
141+
String useThisToMatch = output.substring(firstTask, firstTry).trim();
143142
return Selfie.expectSelfie(useThisToMatch);
144143
}
145144
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ private void taskIsUpToDate(String task, boolean upToDate) throws IOException {
197197

198198
List<String> expected = outcomes(buildResult, upToDate ? TaskOutcome.UP_TO_DATE : TaskOutcome.SUCCESS);
199199
List<String> notExpected = outcomes(buildResult, upToDate ? TaskOutcome.SUCCESS : TaskOutcome.UP_TO_DATE);
200-
boolean everythingAsExpected = !expected.isEmpty() && notExpected.isEmpty() && buildResult.getTasks().size() - 1 == expected.size();
200+
boolean everythingAsExpected = !expected.isEmpty() && notExpected.isEmpty() && buildResult.getTasks().size() == expected.size();
201201
if (!everythingAsExpected) {
202202
fail("Expected all tasks to be " + (upToDate ? TaskOutcome.UP_TO_DATE : TaskOutcome.SUCCESS) + ", but instead was\n" + buildResultToString(buildResult));
203203
}

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,4 +151,40 @@ public void predeclaredUndeclared() throws IOException {
151151
Assertions.assertThat(gradleRunner().withArguments("spotlessApply").buildAndFail().getOutput())
152152
.contains("Could not find method spotlessPredeclare() for arguments");
153153
}
154+
155+
@Test
156+
void nonPredeclaredSupportsIsolatedProjects() throws IOException {
157+
setFile("gradle.properties").toContent("org.gradle.unsafe.isolated-projects=true");
158+
setFile("build.gradle").toLines(
159+
"plugins {",
160+
" id 'com.diffplug.spotless'",
161+
"}",
162+
"repositories { mavenCentral() }",
163+
"",
164+
"spotless {",
165+
" java {",
166+
" target file('test.java')",
167+
" googleJavaFormat('1.17.0')",
168+
" }",
169+
"}");
170+
createNSubprojects();
171+
gradleRunner().withArguments("spotlessApply").build();
172+
}
173+
174+
@Test
175+
void predeclaredRequiresNonIsolatedProjects() throws IOException {
176+
setFile("gradle.properties").toContent("org.gradle.unsafe.isolated-projects=true");
177+
setFile("build.gradle").toLines(
178+
"plugins {",
179+
" id 'com.diffplug.spotless'",
180+
"}",
181+
"repositories { mavenCentral() }",
182+
"spotless { predeclareDeps() }",
183+
"spotlessPredeclare {",
184+
" java { googleJavaFormat('1.17.0') }",
185+
"}");
186+
createNSubprojects();
187+
Assertions.assertThat(gradleRunner().withArguments("spotlessApply").buildAndFail().getOutput())
188+
.contains("Cannot access project");
189+
}
154190
}

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@ void duplicateConfigs() throws IOException {
4343
setFile("gradle.properties").toLines();
4444
String newestSupported = gradleRunner().withArguments("spotlessCheck").build().getOutput();
4545
Assertions.assertThat(newestSupported.replace("\r", ""))
46-
.startsWith(
47-
"> Task :spotlessInternalRegisterDependencies\n")
4846
.contains(
4947
"> Task :sub:spotlessJava\n",
5048
"> Task :sub:spotlessJavaCheck\n",

0 commit comments

Comments
 (0)