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

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
8 changes: 4 additions & 4 deletions plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -194,16 +194,16 @@ tasks.named<Test>("test") {
)
}

val testGradle4 = tasks.register<Test>("testGradle4") {
systemProperty("org.openrewrite.test.gradleVersion", "4.0")
val testGradle4Dot10 = tasks.register<Test>("testGradle4Dot10") {
systemProperty("org.openrewrite.test.gradleVersion", "4.10")
systemProperty("jarLocationForTest", tasks.named<Jar>("jar").get().archiveFile.get().asFile.absolutePath)
// Gradle 4.0 predates support for Java 11
// Gradle 4.10 predates support for Java 11
javaLauncher.set(javaToolchains.launcherFor {
languageVersion.set(JavaLanguageVersion.of(8))
})
}
tasks.named("check").configure {
dependsOn(testGradle4)
dependsOn(testGradle4Dot10)
}

configure<LicenseExtension> {
Expand Down
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.

Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,11 @@
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.api.specs.Specs;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;

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

public class RewriteDryRunTask extends AbstractRewriteTask {

Expand All @@ -34,7 +32,15 @@ public class RewriteDryRunTask extends AbstractRewriteTask {
// On Gradle 4.0 annotating something returning a Path with @OutputFile triggers a bug that deadlocks Gradle
jbduncan marked this conversation as resolved.
Show resolved Hide resolved
@OutputFile
public File getReportPath() {
return getProject().getBuildDir().toPath().resolve("reports").resolve("rewrite").resolve("rewrite.patch").toFile();
return getProjectLayout()
.getBuildDirectory()
.get()
.getAsFile()
.toPath()
.resolve("reports")
.resolve("rewrite")
.resolve("rewrite.patch")
.toFile();
}

@Inject
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 the original author or authors.
* Copyright ${year} the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
96 changes: 87 additions & 9 deletions plugin/src/main/java/org/openrewrite/gradle/RewritePlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,33 @@
*/
package org.openrewrite.gradle;

import org.gradle.api.*;
import org.gradle.api.Plugin;
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.quality.CheckstyleExtension;
import org.gradle.api.plugins.quality.CheckstylePlugin;
import org.gradle.api.provider.Provider;

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 @@ -37,6 +53,8 @@
@SuppressWarnings("unused")
public class RewritePlugin implements Plugin<Project> {

private Set<File> resolvedDependencies;

public void apply(Project project) {
boolean isRootProject = project == project.getRootProject();
if (!isRootProject && project.getRootProject().getPluginManager().hasPlugin("org.openrewrite.rewrite")) {
Expand All @@ -51,25 +69,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 @@ -127,4 +141,68 @@ 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-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())
);
}
}