Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #227: Incompatible with the configuration cache #228

Merged
merged 17 commits into from
Aug 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,41 @@
package org.openrewrite.gradle;

import org.gradle.api.DefaultTask;
import org.gradle.api.file.ProjectLayout;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.options.Option;
import org.gradle.util.GradleVersion;

import javax.inject.Inject;
import java.io.File;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public abstract class AbstractRewriteTask extends DefaultTask {
protected ResolveRewriteDependenciesTask resolveDependenciesTask;
protected Provider<Set<File>> resolvedDependencies;
protected boolean dumpGcActivity;
protected GradleProjectParser gpp;
protected RewriteExtension extension;

protected AbstractRewriteTask() {
if (GradleVersion.current().compareTo(GradleVersion.version("7.4")) >= 0) {
notCompatibleWithConfigurationCache("org.openrewrite.rewrite needs to parse the whole project");
}
}

public <T extends AbstractRewriteTask> T setExtension(RewriteExtension extension) {
this.extension = extension;
//noinspection unchecked
return (T) this;
}

public <T extends AbstractRewriteTask> T setResolveDependenciesTask(ResolveRewriteDependenciesTask resolveDependenciesTask) {
this.resolveDependenciesTask = resolveDependenciesTask;
this.dependsOn(resolveDependenciesTask);
public <T extends AbstractRewriteTask> T setResolvedDependencies(Provider<Set<File>> resolvedDependencies) {
this.resolvedDependencies = resolvedDependencies;
//noinspection unchecked
return (T) this;
}
Expand All @@ -55,16 +65,25 @@ public boolean isDumpGcActivity() {
return dumpGcActivity;
}

@Inject
public ProjectLayout getProjectLayout() {
throw new AssertionError("unexpected; getProjectLayout() should be overridden by Gradle");
}

@Internal
protected <T extends GradleProjectParser> T getProjectParser() {
if (gpp == null) {
if (extension == null) {
throw new IllegalArgumentException("Must configure extension");
}
if (resolveDependenciesTask == null) {
throw new IllegalArgumentException("Must configure resolveDependenciesTask");
if (resolvedDependencies == null) {
throw new IllegalArgumentException("Must configure resolvedDependencies");
}
Set<File> deps = resolvedDependencies.getOrNull();
if (deps == null) {
deps = Collections.emptySet();
}
Set<Path> classpath = resolveDependenciesTask.getResolvedDependencies().stream()
Set<Path> classpath = deps.stream()
.map(File::toPath)
.collect(Collectors.toSet());
gpp = new DelegatingProjectParser(getProject(), extension, classpath);
Expand Down

This file was deleted.

17 changes: 11 additions & 6 deletions plugin/src/main/java/org/openrewrite/gradle/RewriteDryRunTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,22 @@
import org.gradle.api.tasks.TaskAction;

import javax.inject.Inject;
import java.io.File;
import java.nio.file.Path;

public class RewriteDryRunTask extends AbstractRewriteTask {

private static final Logger logger = Logging.getLogger(RewriteDryRunTask.class);

// This must return File, rather than Path.
// On Gradle 4.0 annotating something returning a Path with @OutputFile triggers a bug that deadlocks Gradle
@OutputFile
public File getReportPath() {
return getProject().getLayout().getBuildDirectory().get().getAsFile().toPath().resolve("reports").resolve("rewrite").resolve("rewrite.patch").toFile();
public Path getReportPath() {
return getProjectLayout()
.getBuildDirectory()
.get()
.getAsFile()
.toPath()
.resolve("reports")
.resolve("rewrite")
.resolve("rewrite.patch");
}

@Inject
Expand All @@ -44,6 +49,6 @@ public RewriteDryRunTask() {

@TaskAction
public void run() {
getProjectParser().dryRun(getReportPath().toPath(), dumpGcActivity, throwable -> logger.info("Error during rewrite dry run", throwable));
getProjectParser().dryRun(getReportPath(), dumpGcActivity, throwable -> logger.info("Error during rewrite dry run", throwable));
}
}
93 changes: 85 additions & 8 deletions plugin/src/main/java/org/openrewrite/gradle/RewritePlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,31 @@
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.artifacts.dsl.DependencyHandler;
import org.gradle.api.attributes.Attribute;
import org.gradle.api.attributes.Bundling;
import org.gradle.api.attributes.Category;
import org.gradle.api.attributes.LibraryElements;
import org.gradle.api.attributes.Usage;
import org.gradle.api.attributes.java.TargetJvmEnvironment;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.plugins.JavaPluginConvention;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.plugins.quality.CheckstyleExtension;
import org.gradle.api.plugins.quality.CheckstylePlugin;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.SourceSetContainer;

import java.io.File;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;

import static org.gradle.api.attributes.Bundling.BUNDLING_ATTRIBUTE;
import static org.gradle.api.attributes.java.TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE;

/**
* When applied to the root project of a multi-project build, applies to all subprojects.
Expand All @@ -41,6 +55,8 @@
@SuppressWarnings("unused")
public class RewritePlugin implements Plugin<Project> {

private Set<File> resolvedDependencies;

@Override
public void apply(Project project) {
boolean isRootProject = project == project.getRootProject();
Expand All @@ -56,25 +72,21 @@ public void apply(Project project) {
// Rewrite module dependencies put here will be available to all rewrite tasks
Configuration rewriteConf = project.getConfigurations().maybeCreate("rewrite");

// We use this method of task creation because it works on old versions of Gradle
// Don't replace with TaskContainer.register() (introduced in 4.9), or another overload of create() (introduced in 4.7)
ResolveRewriteDependenciesTask resolveRewriteDependenciesTask = project.getTasks().create("rewriteResolveDependencies", ResolveRewriteDependenciesTask.class)
.setExtension(extension)
.setConfiguration(rewriteConf);
Provider<Set<File>> resolvedDependenciesProvider = project.provider(() -> getResolvedDependencies(project, extension, rewriteConf));

RewriteRunTask rewriteRun = project.getTasks().create("rewriteRun", RewriteRunTask.class)
.setExtension(extension)
.setResolveDependenciesTask(resolveRewriteDependenciesTask);
.setResolvedDependencies(resolvedDependenciesProvider);
rewriteRun.dependsOn(rewriteConf);

RewriteDryRunTask rewriteDryRun = project.getTasks().create("rewriteDryRun", RewriteDryRunTask.class)
.setExtension(extension)
.setResolveDependenciesTask(resolveRewriteDependenciesTask);
.setResolvedDependencies(resolvedDependenciesProvider);
rewriteDryRun.dependsOn(rewriteConf);

RewriteDiscoverTask rewriteDiscover = project.getTasks().create("rewriteDiscover", RewriteDiscoverTask.class)
.setExtension(extension)
.setResolveDependenciesTask(resolveRewriteDependenciesTask);
.setResolvedDependencies(resolvedDependenciesProvider);
rewriteDiscover.dependsOn(rewriteConf);

if (isRootProject) {
Expand Down Expand Up @@ -138,4 +150,69 @@ private static void configureProject(Project project, RewriteExtension extension
}));
});
}

private Set<File> getResolvedDependencies(Project project, RewriteExtension extension, Configuration rewriteConf) {
if (resolvedDependencies == null) {
Dependency[] dependencies = Stream.concat(
knownRewriteDependencies(extension, project.getDependencies()),
rewriteConf.getDependencies().stream()
).toArray(Dependency[]::new);
// By using a detached configuration, we separate this dependency resolution from the rest of the project's
// configuration. This also means that Gradle has no criteria with which to select between variants of
// dependencies which expose differing capabilities. So those must be manually configured
Configuration detachedConf = project.getConfigurations().detachedConfiguration(dependencies);

try {
ObjectFactory objectFactory = project.getObjects();
detachedConf.attributes(attributes -> {
// Adapted from org.gradle.api.plugins.jvm.internal.DefaultJvmEcosystemAttributesDetails
attributes.attribute(Category.CATEGORY_ATTRIBUTE, objectFactory.named(Category.class, Category.LIBRARY));
attributes.attribute(Usage.USAGE_ATTRIBUTE, objectFactory.named(Usage.class, Usage.JAVA_RUNTIME));
attributes.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objectFactory.named(LibraryElements.class, LibraryElements.JAR));
attributes.attribute(BUNDLING_ATTRIBUTE, objectFactory.named(Bundling.class, Bundling.EXTERNAL));
try {
attributes.attribute(TARGET_JVM_ENVIRONMENT_ATTRIBUTE, objectFactory.named(TargetJvmEnvironment.class, TargetJvmEnvironment.STANDARD_JVM));
} catch (NoClassDefFoundError e) {
// Old versions of Gradle don't have the class TargetJvmEnvironment and that's OK, we can always
// try this attribute instead
attributes.attribute(Attribute.of("org.gradle.jvm.environment", String.class), "standard-jvm");
}
});
} catch (NoClassDefFoundError e) {
// Old versions of Gradle don't have all of these attributes and that's OK
}

resolvedDependencies = detachedConf.resolve();
}
return resolvedDependencies;
}

private static Stream<Dependency> knownRewriteDependencies(RewriteExtension extension, DependencyHandler deps) {
String rewriteVersion = extension.getRewriteVersion();
return Stream.of(
deps.create("org.openrewrite:rewrite-core:" + rewriteVersion),
deps.create("org.openrewrite:rewrite-groovy:" + rewriteVersion),
deps.create("org.openrewrite:rewrite-gradle:" + rewriteVersion),
deps.create("org.openrewrite:rewrite-hcl:" + rewriteVersion),
deps.create("org.openrewrite:rewrite-json:" + rewriteVersion),
deps.create("org.openrewrite:rewrite-kotlin:" + extension.getRewriteKotlinVersion()),
deps.create("org.openrewrite:rewrite-java:" + rewriteVersion),
deps.create("org.openrewrite:rewrite-java-21:" + rewriteVersion),
deps.create("org.openrewrite:rewrite-java-17:" + rewriteVersion),
deps.create("org.openrewrite:rewrite-java-11:" + rewriteVersion),
deps.create("org.openrewrite:rewrite-java-8:" + rewriteVersion),
deps.create("org.openrewrite:rewrite-maven:" + rewriteVersion),
deps.create("org.openrewrite:rewrite-properties:" + rewriteVersion),
deps.create("org.openrewrite:rewrite-protobuf:" + rewriteVersion),
deps.create("org.openrewrite:rewrite-xml:" + rewriteVersion),
deps.create("org.openrewrite:rewrite-yaml:" + rewriteVersion),
deps.create("org.openrewrite:rewrite-polyglot:" + extension.getRewritePolyglotVersion()),
deps.create("org.openrewrite.gradle.tooling:model:" + extension.getRewriteGradleModelVersion()),

// This is an optional dependency of rewrite-java needed when projects also apply the checkstyle plugin
deps.create("com.puppycrawl.tools:checkstyle:" + extension.getCheckstyleToolsVersion()),
deps.create("com.fasterxml.jackson.module:jackson-module-kotlin:" + extension.getJacksonModuleKotlinVersion()),
deps.create("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:" + extension.getJacksonModuleKotlinVersion())
);
}
}
Loading
Loading