openrewrite / rewrite-gradle-plugin Goto Github PK
View Code? Open in Web Editor NEWOpenRewrite's Gradle plugin.
License: Apache License 2.0
OpenRewrite's Gradle plugin.
License: Apache License 2.0
Specifying a rewrite.yml is optional, so we don't warn/error if it doesn't exist.
But if someone has specified a non-existent rewrite.yml we should raise some warning.
Difficulty: We check for its existence per task, and there's one task per source set, and many source sets per project. The warning should be displayed exactly once per missing rewrite config file.
from #25
rewriteDryRun
's existing behavior only prints which files would be changed by which visitors, which isn't very useful. It should instead print what the actual changes would be, similar to what git diff would show you after running rewriteRun/rewriteFix
Visitors can now override RefactorVisitor.generate() to produce new sources.
It is the responsibility of the caller, in this case the Gradle plugin, to respond to these new sources and write them to disk in an appropriate location.
When iterating over Change
inside of RewriteFixTask whenever the change has a null
original and a non-null fixed
, it is a new file which needs to be written to disk. SourceFile.getSourcePath()
may be used to determine where this file should go.
Similarly, a change with a non-null
original and a null
fixed indicates that a source file should be deleted.
RewriteWarnTask
should continue not to make any changes to disk, but the text it outputs to the console should be updated to accommodate file generation/deletion
Currently, the maven build plugin does not provide the ability to configure the min/max cycles when running recipes. It currently uses the default of min = 1
and max = 3
.
We should add two configuration options to the plugin to support changing these values.
At the moment, if one runs gradle rewriteDryRun
, then it reports any code that hasn't been refactored.
However, I'd love for the build to fail if rewriteDryRun
reports any such code, so that I know about it at CI time.
It seems to me that a good way forward would be to expose a flag in the extension that, when enabled, makes the build fail if a dry run reports any problems. It would be false
by default to maintain backwards compatibility. So something like:
rewrite {
activeRecipe("com.yourorg.TheRecipe")
failOnBadDryRun = true
}
But I'm open to other ideas!
What do you think, Rewrite team?
From openrewrite/rewrite-micronaut#17:
Gradle plugin only considers source files for processing - any chance the plugin could be amended to also include non-src properties files?
Given the sample:
https://github.com/shanman190/openrewrite-gradle-issue-gh-83
And executing ./gradlew rewriteDryRun
the plugin outputs:
> Task :compileJava NO-SOURCE
> Task :processResources NO-SOURCE
> Task :classes UP-TO-DATE
> Task :compileTestJava NO-SOURCE
> Task :rewriteResolveDependencies
> Task :rewriteDryRun
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/Users/<removed>/.gradle/caches/modules-2/files-2.1/org.openrewrite/rewrite-gradle/7.16.0/1a7a48ffbfdaeeb2ba79b1a0714f4e69d82b67e3/rewrite-gradle-7.16.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/Users/<removed>/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-simple/1.7.30/e606eac955f55ecf1d8edcccba04eb8ac98088dd/slf4j-simple-1.7.30.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.gradle.internal.logging.slf4j.OutputEventListenerBackedLoggerContext]
Using active recipe(s) [com.example.VersionRelocation]
Using active styles(s) []
Validating active recipes
Running recipe(s)...
Applying recipes would make no changes. No report generated.
Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.9.1/userguide/command_line_interface.html#sec:command_line_warnings
BUILD SUCCESSFUL in 24s
2 actionable tasks: 2 executed
As you can see in the sample, it should have rewritten the version from 2.3.12.RELEASE
to 2.4.13
. This same behavior also happens when trying to do ChangeDependencyGroupId
and ChangeDependencyArtifactId
. It feels like it may be that something with org.openrewrite.gradle
effecting the build.gradle
of itself is at play here?
Recipes such as ChangePackage may have renamed camel case packages to their lower case variant.
Presently, the plugin needs to compile against several different libraries (rewrite, jackson, etc). These of course are needed for compilation. However, in order to work around the plugin needing Jackson and not wanting to conflict with the shared plugin classpath, internally it uses it's own dependency configuration and isolated classloader. This works great.
However, we are still leaking these dependencies via the plugin's compileClasspath/runtimeClasspath out to the Gradle plugin classpath. This means that if another plugin depends on Jackson, this plugin influences it's version that it receives.
To correct this, we should move from implementation to compileOnly and testImplementation/runtimeOnly so that we no longer leak out the internal classpath that the plugin needs at runtime and will gain via it's internal dependency configuration rewriteDependencies
.
See: https://github.com/openrewrite/rewrite-gradle-plugin/blob/main/plugin/src/main/java/org/openrewrite/gradle/AbstractRewriteTask.java#L77-L80
Consider updating the generated name/id for gradlePlugin
to set the metadata for rewrite-gradle-plugin
to result in a GAV similar to Maven, e.g. org.openrewrite.maven:rewrite-maven-plugin
, but for gradle; so, org.openrewrite.gradle:rewrite-gradle-plugin
. Currently, the generated metadata for the rewrite-gradle-plugin
results in referencing the plugin as org.openrewrite.rewrite
. This is acceptable for gradle, but when publishing this to Maven, it results in gav coordinates of org.openrewrite:plugin
(https://oss.sonatype.org/service/local/repositories/snapshots/content/org/openrewrite/plugin/maven-metadata.xml). And having to do something a little peculiar with pluginManagement
when publishing snapshots:
pluginManagement {
resolutionStrategy {
eachPlugin {
if (requested.id.namespace == "org.openrewrite") {
useModule("org.openrewrite:plugin:${requested.version}")
}
}
}
...
}
From #84
In order to simplify execution and bring the gradle-plugin into alignment with how the maven-plugin and other services work, consider consolidating per-souceset tasks into single tasks.
The following thread dump was collected and while working with a design partner. This may be due to Virus scanning software installed on the machine, but we should investigate how to speed this up.
"Execution worker for ':' Thread 13" #466 prio=5 os_prio=31 cpu=633447.32ms elapsed=730.02s tid=0x00007ffdc8f87000 nid=0x57c03 runnable [0x000070002d677000]
java.lang.Thread.State: RUNNABLE
at sun.nio.fs.UnixNativeDispatcher.realpath0([email protected]/Native Method)
at sun.nio.fs.UnixNativeDispatcher.realpath([email protected]/UnixNativeDispatcher.java:272)
at sun.nio.fs.UnixPath.toRealPath([email protected]/UnixPath.java:857)
at org.openrewrite.gradle.AbstractRewriteTask.toRealPath(AbstractRewriteTask.java:448)
at org.openrewrite.gradle.AbstractRewriteTask$$Lambda$1135/0x0000000800e69c40.apply(Unknown Source)
at java.util.stream.ReferencePipeline$3$1.accept([email protected]/ReferencePipeline.java:195)
at java.util.stream.ReferencePipeline$3$1.accept([email protected]/ReferencePipeline.java:195)
at java.util.Iterator.forEachRemaining([email protected]/Iterator.java:133)
at java.util.Spliterators$IteratorSpliterator.forEachRemaining([email protected]/Spliterators.java:1801)
at java.util.stream.AbstractPipeline.copyInto([email protected]/AbstractPipeline.java:484)
at java.util.stream.AbstractPipeline.wrapAndCopyInto([email protected]/AbstractPipeline.java:474)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential([email protected]/ReduceOps.java:913)
at java.util.stream.AbstractPipeline.evaluate([email protected]/AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect([email protected]/ReferencePipeline.java:578)
at org.openrewrite.gradle.AbstractRewriteTask.parse(AbstractRewriteTask.java:251)
at org.openrewrite.gradle.AbstractRewriteTask.lambda$listResults$3(AbstractRewriteTask.java:191)
at org.openrewrite.gradle.AbstractRewriteTask$$Lambda$1103/0x0000000800e66040.apply(Unknown Source)
at java.util.stream.ReferencePipeline$7$1.accept([email protected]/ReferencePipeline.java:271)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining([email protected]/ArrayList.java:1655)
at java.util.stream.AbstractPipeline.copyInto([email protected]/AbstractPipeline.java:484)
at java.util.stream.AbstractPipeline.wrapAndCopyInto([email protected]/AbstractPipeline.java:474)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential([email protected]/ReduceOps.java:913)
at java.util.stream.AbstractPipeline.evaluate([email protected]/AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect([email protected]/ReferencePipeline.java:578)
at org.openrewrite.gradle.AbstractRewriteTask.listResults(AbstractRewriteTask.java:192)
at org.openrewrite.gradle.RewriteDryRunTask.run(RewriteDryRunTask.java:69)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0([email protected]/Native Method)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke([email protected]/NativeMethodAccessorImpl.java:62)
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke([email protected]/DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke([email protected]/Method.java:566)
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:104)
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:58)
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:51)
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:29)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$2.run(ExecuteActionsTaskExecuter.java:494)
at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
Currently the Gradle plugin allows only a single config file to be specified. Typically something like:
rewrite {
configLocation = "rewrite.yaml"
}
This config location is always interpreted as a file path on the local machine.
To allow for many repositories to easily share centrally hosted configuration, we should allow URIs in this field.
Similarly, there might be one (or more) common configs in addition to one (or more) local, project-specific configurations.
Therefore configLocation
should accept a list, rather than only a singular entry.
No one really uses the Gradle plugin right now - we haven't even published it properly to the gradle plugin portal - so backwards compatibility isn't particularly important in this case.
See: openrewrite/rewrite-maven-plugin#265
Publish rewrite-gradle-plugin snapshots to ossrh snapshots.
This will make it more convenient to consume and validate changes prior to release.
Be aware that to resolve plugins from anywhere other than the gradle plugin portal, you need a snippet like this in the settings.gradle.kts
pluginManagement {
repositories {
// ...
maven {
url = uri("https://oss.sonatype.org/content/repositories/snapshots/")
}
// ...
// you'll likely also need this if you don't have a pluginManagement section already:
gradlePluginPortal()
// ...
}
}
Gradle plugin portal doesn't accept snapshots, but that's alright. We'll push snapshots to OSSRH, and can keep publishing releases just to gradlePluginPortal.
Enable the ability to run the rewrite-gradle-plugin against our own openrewrite repositories.
These are fine to start trialing.
The Gradle plugin creates a dependency configuration called rewrite. This is where users declare any recipe modules they want to be able to run. That configuration is resolved when any of the rewrite tasks run and the resulting jars stuffed into a class loader.
This works pretty well unless custom dependency resolution policies or a plugin like the spring dependency management plugin interfere with normal dependency resolution.
We should try packing the core rewrite dependencies and jackson into the plugin's own jar and loading them from there.
Based on this discussion in the community slack.
"warn" and "fix" are legacy names from when we thought quite a bit differently about the intended usage of these things.
"rewriteFix" should be renamed to "rewriteRun".
"rewriteWarn" should be renamed to "rewriteDryRun".
Do the same thing here that we did in openrewrite/rewrite-maven-plugin#344
Mirroring the discussion in openrewrite/rewrite-maven-plugin#159. The same should be done for the gradle plugin.
I'm trying to run some Java recipes. With v5.5.0 or v5.6.0 running rewriteRun
or rewriteDryRun
fails with
Caused by: java.lang.RuntimeException: java.lang.NoSuchMethodException: org.openrewrite.java.marker.JavaProvenance.<init>(java.util.UUID, java.lang.String, java.lang.String, org.openrewrite.java.marker.JavaProvenance$BuildTool, org.openrewrite.java.marker.JavaProvenance$JavaVersion, java.util.Set, org.openrewrite.java.marker.JavaProvenance$Publication)
at org.openrewrite.gradle.RewriteReflectiveFacade$JavaProvenanceBuilder.build(RewriteReflectiveFacade.java:375)
at org.openrewrite.gradle.AbstractRewriteTask.parse(AbstractRewriteTask.java:212)
... 125 more
Caused by: java.lang.NoSuchMethodException: org.openrewrite.java.marker.JavaProvenance.<init>(java.util.UUID, java.lang.String, java.lang.String, org.openrewrite.java.marker.JavaProvenance$BuildTool, org.openrewrite.java.marker.JavaProvenance$JavaVersion, java.util.Set, org.openrewrite.java.marker.JavaProvenance$Publication)
at org.openrewrite.gradle.RewriteReflectiveFacade$JavaProvenanceBuilder.build(RewriteReflectiveFacade.java:371)
... 126 more
I tried this in a larger project but a barebones project with no source, settings.gradle
rootProject.name = 'foo'
and build.gradle
plugins {
id 'java'
id 'org.openrewrite.rewrite' version '5.5.0'
}
repositories {
mavenCentral()
}
rewrite {
activeRecipe('org.openrewrite.java.cleanup.UnnecessaryThrows')
}
fails the same way. Downgrading to version 5.4.1 works.
All gradle plugins included in the same build share the same classpath at runtime.
This can be problematic when plugins used in the same build depend on different versions of the same dependencies. We've persistently had issues with our dependency on jackson conflicting with other gradle plugins that also depend on jackson.
To resolve this, we should remove our compile-time dependencies on rewrite and instead construct a detached Gradle dependency configuration at runtime, resolve the rewrite dependencies there, and construct our own isolated classloader through which we load & use rewrite at runtime.
Currently, documentation for rewrite-gradle-plugin instructs users to add rewrite recipe dependencies (i.e. rewrite-testing-frameworks) as compileOnly dependencies on the project being mutated. It's not entirely clear why, but compileOnly doesn't work when running rewrite-testing-frameworks with netflix zuul; using implementation scope does work. However, needing to use implementation scoped dependencies is not ideal because it will pollute the application's real dependencies. 2 options were discussed as potential solutions with different benefits.
There is a medium priority vulnerability for Kotlin 1.5.x., this dependency is being brought in transitively through the jackson-kotlin-module:2.13.2
We cannot address this issue until there is a new release of jackson.
https://mvnrepository.com/artifact/com.fasterxml.jackson.module/jackson-module-kotlin
Create a new type of task that lists all of the available Recipes and their visitors.
When this task is complete running ./gradlew rewriteDiscover
on a project which has this on its classpath and applies this plugin should result in console output similar to:
>./gradlew rewriteDiscover
Found 1 active recipes and 1 total recipes.
Active Recipe Names:
org.openrewrite.mockito
Recipes:
name: org.openrewrite.mockito
include: org.openrewrite.mockito.*
exclude:
visitors:
org.openrewrite.mockito.MockAsOuterClass
org.openrewrite.mockito.ArgumentMatchersAny
org.openrewrite.mockito.InvocationOnMockGetArgument
Implementing this will involve creating a class called RewriteDiscoverTask, the start of which will probably look something like this:
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.api.tasks.TaskAction;
import org.openrewrite.RefactorPlan;
import org.openrewrite.RefactorVisitor;
import java.util.Collection;
import java.util.List;
import java.util.Set;
public class RewriteDiscoverTask extends AbstractRewriteTask {
private static Logger log = Logging.getLogger(RewriteDiscoverTask.class);
@Override
protected Logger getLog() {
return log;
}
@TaskAction
public void run() {
RefactorPlan plan = plan();
Set<String> activeRecipes = getActiveRecipes();
// Print active recipes via log.quiet("message to print")
List<GradleRecipeConfiguration> recipes = getRecipes();
for(GradleRecipeConfiguration recipe : recipes) {
// Print recipe name
Collection<RefactorVisitor<?>> visitors = plan.visitors(recipe.name);
for(RefactorVisitor<?> visitor : visitors) {
// Print visitor name
}
}
}
}
Tasks of this type must then be registered on the Gradle project inside of RewritePlugin
.
The configuration of these newly registered RewriteDiscoverTasks
should end up being very similar to the configuration for the RewriteFixTask
s in the same area.
Right now if you set a search recipe as active it will run but produce no output. This is because the plugins are not configured to use any SearchResultPrinters. The plugins should use the default SearchResultPrinter for a given SourceFile (see openrewrite/rewrite#412) to accomplish this, so that when the marker is reified to a comment it does not break the resulting source code.
rewrite-testing-frameworks takes a dependency on junit4 so that junit4 can be removed. But if people leave rewrite-testing-frameworks as a compileOnly
or testCompileOnly
dependency then junit4 will always be on their class path.
So this is issue is to add a new configuration just for recipes, call it "rewrite" or "rewriteRecipe" or something along those lines.
No other configuration will inherit from that one so we wont have to worry about cluttering up any classpaths but our own.
We should still also look at the compile-time dependencies since we have a longer term aspiration that framework/library authors package upgrade recipes inside their jars. For that to work recipes need to continue to be discoverable from the compile classpath.
For parity with Maven plugin
The plugin is currently compatible with 4.7+.
Let's bring that down to 4.0 so that more people can take advantage of automated refactoring.
Rewrite-spring recipes RemoveObsoleteRunners and RunnerToExtension are both unable to be deserialized from declarative recipe lists in rewrite-gradle-plugin. We've observed that both contain an @Option
annotated property that is of type List<String>
. The exception observed is
java.lang.IllegalArgumentException: Could not resolve type id 'org.openrewrite.java.testing.junit5.RemoveObsoleteRunners' as a subtype of `org.openrewrite.Recipe`: no such class found
though based on observing the classpath, Recipe and RemoveObsoleteRunners are both definitely present, so we think this exception may be a red herring for the real issue.
The JavaPaths will be added as quarks since the JavaPaths are not added to alreadyParsed
.
On the assumption that most builds, even larger ones, will want to configure rewrite in a single place by default. Will continue to be over-rideble on a per-project basis.
To affect this change in RewriteExtension we just need to change this line from:
configFile = project.file("rewrite.yml");
to this:
configFile = project.getRootProject().file("rewrite.yml");
Users should be able to specify custom endpoint the metrics should be sent to.
We have some defunct infrastructure for this already, but it needs to be updated and turned back no.
As the title implies. Consolidate output naming with maven plugin.
As the title implies. Handle any reasons why the tests are ignored.
The DefaultProjectParser will not be able to move Quark SourceFiles by deleting and writing their contents to the new location since the Quark charset is unknown.
Related to: openrewrite/rewrite-maven-plugin#366
When running rewrite-testing-frameworks against netflix zuul via rewrite-gradle-plugin gw rewriteRun
, the recipes make modifications to multiple source files, and then a compile is run with many errors due to the fact that we don't currently have a way to change the junit dependencies in build.gradle. As far as I can tell, the rewriteRun task should not be running a compile. This may be due to some gradle configuration in netflix zuul, or perhaps something in the rewrite gradle plugin is running a build after rewriteRun. Investigate, and If it's the latter, prevent rewriteRun from running compile.
Caused by: java.lang.StackOverflowError
at org.openrewrite.SourceFile.printAllAsBytes(SourceFile.java:63)
at org.openrewrite.remote.Remote.printAll(Remote.java:65)
at org.openrewrite.SourceFile.printAllAsBytes(SourceFile.java:63)
at org.openrewrite.remote.Remote.printAll(Remote.java:65)
At the moment, when I import rewrite-gradle-plugin and run check
, it doesn't seem to run any task from rewrite-gradle-plugin such as rewriteDryRun
. This is counter-intuitive for me, because I'm used to Spotless - a code formatting plugin - automatically checking if my code is formatted if I run check
.
It's not a big problem, because it's easy to tell rewriteDryRun
to run when check
is called, like so:
tasks.named("check").configure {
dependsOn(tasks.named("rewriteDryRun"))
}
However, I'd love for the status quo to change so that I don't need this piece of code anymore.
Consider hooking rewriteDryRun
into check
so that when check
runs, then rewriteDryRun
does too.
Alternatively, consider exposing a new flag in the extension that does all this when enabled. For example:
rewrite {
activeRecipe(...)
doDryRunOnCheck = true
}
We need to add the QuarkParser as the last parser in the resource parser. This will pick up any misc. files that have been missed by Rewrite's other parsers. Additionally, by putting this in the ResourceParse, any files within the main/test folders will have the proper SourceSet
assigned to them.
When someone opens their gradle build file to add an entry to the gradle plugins block, they know that they're applying a gradle plugin. Including "gradle-plugin" in the name is kind of silly.
see: #20
Remove the deprecated tasks rewriteWarn and rewriteFix
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.