diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/plugins/UpgradePluginVersion.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/plugins/UpgradePluginVersion.java index 61898a8c868..05d69821efb 100644 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/plugins/UpgradePluginVersion.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/plugins/UpgradePluginVersion.java @@ -28,7 +28,6 @@ import org.openrewrite.internal.ListUtils; import org.openrewrite.internal.StringUtils; import org.openrewrite.java.JavaVisitor; -import org.openrewrite.java.MethodMatcher; import org.openrewrite.java.tree.Expression; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.JavaType; @@ -56,7 +55,6 @@ @EqualsAndHashCode(callSuper = false) public class UpgradePluginVersion extends ScanningRecipe { private static final String GRADLE_PROPERTIES_FILE_NAME = "gradle.properties"; - private static final MethodMatcher VERSION_MATCHER = new MethodMatcher("org.gradle.plugin.use.PluginDependencySpec version(..)", true); @EqualsAndHashCode.Exclude transient MavenMetadataFailures metadataFailures = new MavenMetadataFailures(this); @@ -110,23 +108,6 @@ public DependencyVersionState getInitialValue(ExecutionContext ctx) { return new DependencyVersionState(); } - @SuppressWarnings("BooleanMethodIsAlwaysInverted") - private boolean isPluginVersion(Cursor cursor) { - if (!(cursor.getValue() instanceof J.MethodInvocation)) { - return false; - } - J.MethodInvocation maybeVersion = cursor.getValue(); - if (!VERSION_MATCHER.matches(maybeVersion, true)) { - return false; - } - Cursor parent = cursor.dropParentUntil(it -> (it instanceof J.MethodInvocation) || it == Cursor.ROOT_VALUE); - if (!(parent.getValue() instanceof J.MethodInvocation)) { - return false; - } - J.MethodInvocation maybePlugins = parent.getValue(); - return "plugins".equals(maybePlugins.getSimpleName()); - } - @Override public TreeVisitor getScanner(DependencyVersionState acc) { @@ -164,37 +145,18 @@ public J visitVariable(J.VariableDeclarations.NamedVariable variable, ExecutionC @Override public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { J.MethodInvocation m = (J.MethodInvocation) super.visitMethodInvocation(method, ctx); - if (!isPluginVersion(getCursor())) { - return m; - } - assert m.getSelect() != null; - List pluginArgs = ((J.MethodInvocation) m.getSelect()).getArguments(); - if (!(pluginArgs.get(0) instanceof J.Literal)) { - return m; - } - String pluginId; - if ("kotlin".equals(((J.MethodInvocation) m.getSelect()).getSimpleName())) { - pluginId = "kotlin"; - } else { - pluginId = literalValue(pluginArgs.get(0)); - } - if (pluginId == null || !StringUtils.matchesGlob(pluginId, pluginIdPattern)) { + + GradlePlugin plugin = new GradlePlugin.Matcher().pluginIdPattern(pluginIdPattern).get(getCursor()).orElse(null); + if (plugin == null || plugin.getPluginId() == null) { return m; } + String pluginId = plugin.getPluginId(); List versionArgs = m.getArguments(); try { - String currentVersion = literalValue(versionArgs.get(0)); - if (currentVersion != null) { - String resolvedVersion; - if ("kotlin".equals(pluginId)) { - String fullPluginId = String.format("org.jetbrains.%s.%s", pluginId, literalValue(pluginArgs.get(0))); - resolvedVersion = new DependencyVersionSelector(metadataFailures, gradleProject, gradleSettings) - .select(new GroupArtifactVersion(fullPluginId, fullPluginId + ".gradle.plugin", currentVersion), "classpath", newVersion, versionPattern, ctx); - } else { - resolvedVersion = new DependencyVersionSelector(metadataFailures, gradleProject, gradleSettings) - .select(new GroupArtifactVersion(pluginId, pluginId + ".gradle.plugin", currentVersion), "classpath", newVersion, versionPattern, ctx); - } + if (plugin.getVersion() != null) { + String resolvedVersion = new DependencyVersionSelector(metadataFailures, gradleProject, gradleSettings) + .select(new GroupArtifactVersion(pluginId, pluginId + ".gradle.plugin", plugin.getVersion()), "classpath", newVersion, versionPattern, ctx); acc.pluginIdToNewVersion.put(pluginId, resolvedVersion); } else if (versionArgs.get(0) instanceof G.GString) { G.GString gString = (G.GString) versionArgs.get(0); @@ -204,12 +166,8 @@ public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) G.GString.Value gStringValue = (G.GString.Value) gString.getStrings().get(0); String versionVariableName = gStringValue.getTree().toString(); - String resolverPluginId = pluginId; - if ("kotlin".equals(pluginId)) { - resolverPluginId = String.format("org.jetbrains.%s.%s", pluginId, literalValue(pluginArgs.get(0))); - } String resolvedPluginVersion = new DependencyVersionSelector(metadataFailures, gradleProject, gradleSettings) - .select(new GroupArtifact(resolverPluginId, resolverPluginId + ".gradle.plugin"), "classpath", newVersion, versionPattern, ctx); + .select(new GroupArtifact(pluginId, pluginId + ".gradle.plugin"), "classpath", newVersion, versionPattern, ctx); acc.versionPropNameToPluginId.put(versionVariableName, pluginId); assert resolvedPluginVersion != null; @@ -217,18 +175,14 @@ public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) } else if (versionArgs.get(0) instanceof J.Identifier) { J.Identifier identifier = (J.Identifier) versionArgs.get(0); String versionVariableName = identifier.getSimpleName(); - String resolverPluginId = pluginId; - if ("kotlin".equals(pluginId)) { - resolverPluginId = String.format("org.jetbrains.%s.%s", pluginId, literalValue(pluginArgs.get(0))); - } String localCurrentVersion = localVariableValues.get(versionVariableName); String resolvedPluginVersion; if (localCurrentVersion != null) { resolvedPluginVersion = new DependencyVersionSelector(metadataFailures, gradleProject, gradleSettings) - .select(new GroupArtifactVersion(resolverPluginId, resolverPluginId + ".gradle.plugin", localCurrentVersion), "classpath", newVersion, versionPattern, ctx); + .select(new GroupArtifactVersion(pluginId, pluginId + ".gradle.plugin", localCurrentVersion), "classpath", newVersion, versionPattern, ctx); } else { resolvedPluginVersion = new DependencyVersionSelector(metadataFailures, gradleProject, gradleSettings) - .select(new GroupArtifact(resolverPluginId, resolverPluginId + ".gradle.plugin"), "classpath", newVersion, versionPattern, ctx); + .select(new GroupArtifact(pluginId, pluginId + ".gradle.plugin"), "classpath", newVersion, versionPattern, ctx); } acc.versionPropNameToPluginId.put(versionVariableName, pluginId); @@ -338,31 +292,21 @@ public Properties visitEntry(Properties.Entry entry, ExecutionContext ctx) { @Override public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + // Match the trait before super to ensure the cursor is unmodified + GradlePlugin plugin = new GradlePlugin.Matcher().pluginIdPattern(pluginIdPattern).get(getCursor()).orElse(null); + J.MethodInvocation m = (J.MethodInvocation) super.visitMethodInvocation(method, ctx); - if (!isPluginVersion(getCursor())) { - return m; - } - assert m.getSelect() != null; - List pluginArgs = ((J.MethodInvocation) m.getSelect()).getArguments(); - String pluginId; - if ("kotlin".equals(((J.MethodInvocation) m.getSelect()).getSimpleName())) { - pluginId = "kotlin"; - } else { - pluginId = literalValue(pluginArgs.get(0)); - } - if (pluginId == null || !StringUtils.matchesGlob(pluginId, pluginIdPattern)) { - return m; - } - List versionArgs = m.getArguments(); - String currentVersion = literalValue(m.getArguments().get(0)); - if (currentVersion == null) { + if (plugin == null || plugin.getPluginId() == null || plugin.getVersion() == null || + !"version".equals(m.getSimpleName())) { return m; } - String resolvedVersion = acc.pluginIdToNewVersion.get(pluginId); + + String resolvedVersion = acc.pluginIdToNewVersion.get(plugin.getPluginId()); if (resolvedVersion == null) { return m; } + List versionArgs = m.getArguments(); return m.withArguments(ListUtils.map(versionArgs, v -> ChangeStringLiteral.withStringValue(v, resolvedVersion))); } diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/trait/GradlePlugin.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/trait/GradlePlugin.java index 0a788d6e5e3..2d53ff1a63c 100644 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/trait/GradlePlugin.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/trait/GradlePlugin.java @@ -141,35 +141,38 @@ public J visitMethodInvocation(J.MethodInvocation method, P p) { return maybeGradlePlugin(cursor, null, null, null, true); } else if (APPLY_DSL_MATCHER.matches(m, true)) { - if (!(m.getArguments().get(0) instanceof J.Literal) || !(m.getSelect() instanceof J.MethodInvocation)) { + Expression applyArg = m.getArguments().get(0).unwrap(); + if (!(applyArg instanceof J.Literal) || !(m.getSelect() instanceof J.MethodInvocation)) { return null; } J.MethodInvocation versionSelect = (J.MethodInvocation) m.getSelect(); + Expression versionArg = versionSelect.getArguments().get(0).unwrap(); if (!PLUGIN_VERSION_DSL_MATCHER.matches(versionSelect, true) || - !(versionSelect.getArguments().get(0) instanceof J.Literal) || + !(versionArg instanceof J.Literal) || !(versionSelect.getSelect() instanceof J.MethodInvocation)) { return null; } J.MethodInvocation idSelect = (J.MethodInvocation) versionSelect.getSelect(); + Expression idArg = idSelect.getArguments().get(0).unwrap(); if (!(PLUGIN_ID_DSL_MATCHER.matches(idSelect, true) || KOTLIN_PLUGIN_DSL_MATCHER.matches(idSelect, true)) || - !(idSelect.getArguments().get(0) instanceof J.Literal)) { + !(idArg instanceof J.Literal)) { return null; } - J.Literal idLiteral = (J.Literal) idSelect.getArguments().get(0); - J.Literal versionLiteral = (J.Literal) versionSelect.getArguments().get(0); - J.Literal applyLiteral = (J.Literal) m.getArguments().get(0); + J.Literal idLiteral = (J.Literal) idArg; + J.Literal versionLiteral = (J.Literal) versionArg; + J.Literal applyLiteral = (J.Literal) applyArg; String pluginId = "kotlin".equals(idSelect.getSimpleName()) ? "org.jetbrains.kotlin." + idLiteral.getValue() : (String) idLiteral.getValue(); String version = (String) versionLiteral.getValue(); boolean applied = Boolean.TRUE.equals(applyLiteral.getValue()); return maybeGradlePlugin(cursor, pluginId, null, version, applied); } else if (PLUGIN_VERSION_DSL_MATCHER.matches(m, true)) { String version = null; - if (m.getArguments().get(0) instanceof J.Literal) { - J.Literal versionLiteral = (J.Literal) m.getArguments().get(0); - version = (String) versionLiteral.getValue(); + Expression versionArg = m.getArguments().get(0).unwrap(); + if (versionArg instanceof J.Literal) { + version = (String) ((J.Literal) versionArg).getValue(); } if (!(m.getSelect() instanceof J.MethodInvocation && @@ -178,19 +181,21 @@ public J visitMethodInvocation(J.MethodInvocation method, P p) { } J.MethodInvocation select = (J.MethodInvocation) m.getSelect(); - if (!(select.getArguments().get(0) instanceof J.Literal)) { + Expression idArg = select.getArguments().get(0).unwrap(); + if (!(idArg instanceof J.Literal)) { return null; } - J.Literal idLiteral = (J.Literal) select.getArguments().get(0); + J.Literal idLiteral = (J.Literal) idArg; String pluginId = "kotlin".equals(select.getSimpleName()) ? "org.jetbrains.kotlin." + idLiteral.getValue() : (String) idLiteral.getValue(); return maybeGradlePlugin(cursor, pluginId, null, version, !withinBlock(cursor, "pluginManagement")); } else if (PLUGIN_ID_DSL_MATCHER.matches(m, true) || KOTLIN_PLUGIN_DSL_MATCHER.matches(m, true)) { - if (!(m.getArguments().get(0) instanceof J.Literal)) { + Expression arg = m.getArguments().get(0).unwrap(); + if (!(arg instanceof J.Literal)) { return null; } - J.Literal literal = (J.Literal) m.getArguments().get(0); + J.Literal literal = (J.Literal) arg; String pluginId = "kotlin".equals(m.getSimpleName()) ? "org.jetbrains.kotlin." + literal.getValue() : (String) literal.getValue(); return maybeGradlePlugin(cursor, pluginId, null, null, !withinBlock(cursor, "pluginManagement")); } @@ -240,12 +245,15 @@ public J visitMethodInvocation(J.MethodInvocation method, P p) { private boolean withinPlugins(Cursor cursor) { Cursor parent = cursor.dropParentUntil(value -> value instanceof J.MethodInvocation || value == Cursor.ROOT_VALUE); - if (parent.isRoot() || !"plugins".equals(((J.MethodInvocation) parent.getValue()).getSimpleName())) { - return false; + while (!parent.isRoot()) { + J.MethodInvocation parentMethod = parent.getValue(); + if ("plugins".equals(parentMethod.getSimpleName())) { + parent = parent.dropParentUntil(value -> value instanceof J.MethodInvocation || value == Cursor.ROOT_VALUE); + return parent.isRoot() || "pluginManagement".equals(((J.MethodInvocation) parent.getValue()).getSimpleName()); + } + parent = parent.dropParentUntil(value -> value instanceof J.MethodInvocation || value == Cursor.ROOT_VALUE); } - - parent = parent.dropParentUntil(value -> value instanceof J.MethodInvocation || value == Cursor.ROOT_VALUE); - return parent.isRoot() || "pluginManagement".equals(((J.MethodInvocation) parent.getValue()).getSimpleName()); + return false; } private boolean isProjectReceiver(Cursor cursor) { diff --git a/rewrite-gradle/src/test/java/org/openrewrite/gradle/plugins/UpgradePluginVersionTest.java b/rewrite-gradle/src/test/java/org/openrewrite/gradle/plugins/UpgradePluginVersionTest.java index 3ed31d4c401..27bb68aa2ae 100644 --- a/rewrite-gradle/src/test/java/org/openrewrite/gradle/plugins/UpgradePluginVersionTest.java +++ b/rewrite-gradle/src/test/java/org/openrewrite/gradle/plugins/UpgradePluginVersionTest.java @@ -62,7 +62,7 @@ void upgradePlugin() { @Test void upgradeKotlinPluginLiteralVersion() { rewriteRun( - spec -> spec.recipe(new UpgradePluginVersion("kotlin", "2.3.0", null)), + spec -> spec.recipe(new UpgradePluginVersion("org.jetbrains.kotlin.*", "2.3.0", null)), buildGradleKts( """ plugins { @@ -81,7 +81,7 @@ void upgradeKotlinPluginLiteralVersion() { @Test void upgradeKotlinPlugin() { rewriteRun( - spec -> spec.recipe(new UpgradePluginVersion("kotlin", "latest.minor", null)), + spec -> spec.recipe(new UpgradePluginVersion("org.jetbrains.kotlin.*", "latest.minor", null)), buildGradleKts( """ plugins { @@ -101,7 +101,7 @@ void upgradeKotlinPlugin() { @Test void upgradeKotlinPluginLocalVariable() { rewriteRun( - spec -> spec.recipe(new UpgradePluginVersion("kotlin", "2.1.0", null)), + spec -> spec.recipe(new UpgradePluginVersion("org.jetbrains.kotlin.*", "2.1.0", null)), buildGradleKts( """ plugins { @@ -126,7 +126,7 @@ void upgradeKotlinPluginLocalVariable() { @Test void upgradeKotlinPluginLocalVariableWithSemverSelector() { rewriteRun( - spec -> spec.recipe(new UpgradePluginVersion("kotlin", "latest.minor", null)), + spec -> spec.recipe(new UpgradePluginVersion("org.jetbrains.kotlin.*", "latest.minor", null)), buildGradleKts( """ plugins { @@ -146,7 +146,7 @@ void upgradeKotlinPluginLocalVariableWithSemverSelector() { @Test void dontDowngradeKotlinPluginLocalVariable() { rewriteRun( - spec -> spec.recipe(new UpgradePluginVersion("kotlin", "1.9.0", null)), + spec -> spec.recipe(new UpgradePluginVersion("org.jetbrains.kotlin.*", "1.9.0", null)), buildGradleKts( """ plugins { @@ -414,6 +414,45 @@ void upgradePluginVersionInBuildGradleNotProperties() { ); } + + @Test + void kotlinDslWithApplyFalse() { + rewriteRun( + spec -> spec.recipe(new UpgradePluginVersion("com.github.johnrengelman.shadow", "7.1.x", null)), + buildGradleKts( + """ + plugins { + id("com.github.johnrengelman.shadow") version "7.1.0" apply false + } + """, + """ + plugins { + id("com.github.johnrengelman.shadow") version "7.1.2" apply false + } + """ + ) + ); + } + + @Test + void groovyDslWithApplyFalse() { + rewriteRun( + spec -> spec.recipe(new UpgradePluginVersion("com.github.johnrengelman.shadow", "7.1.x", null)), + buildGradle( + """ + plugins { + id 'com.github.johnrengelman.shadow' version '7.1.0' apply false + } + """, + """ + plugins { + id 'com.github.johnrengelman.shadow' version '7.1.2' apply false + } + """ + ) + ); + } + @Test void upgradeSpringBootPluginWithoutDependencyManagementEnabled() { rewriteRun( @@ -424,11 +463,11 @@ void upgradeSpringBootPluginWithoutDependencyManagementEnabled() { id 'java' id 'org.springframework.boot' version '2.7.0' } - + repositories { mavenCentral() } - + dependencies { implementation 'javax.servlet:javax.servlet-api:4.0.1' implementation 'org.apache.activemq:activemq-client-jakarta:5.18.2' @@ -439,11 +478,11 @@ void upgradeSpringBootPluginWithoutDependencyManagementEnabled() { id 'java' id 'org.springframework.boot' version '3.2.4' } - + repositories { mavenCentral() } - + dependencies { implementation 'javax.servlet:javax.servlet-api:4.0.1' implementation 'org.apache.activemq:activemq-client-jakarta:5.18.2' @@ -465,11 +504,11 @@ void springBootPluginsAreDependencyManagedVersionAware() { id 'org.springframework.boot' version '2.7.0' id 'io.spring.dependency-management' version '1.1.6' } - + repositories { mavenCentral() } - + dependencies { implementation 'javax.servlet:javax.servlet-api' implementation 'org.apache.activemq:activemq-client-jakarta:5.18.2' @@ -481,11 +520,11 @@ void springBootPluginsAreDependencyManagedVersionAware() { id 'org.springframework.boot' version '3.2.4' id 'io.spring.dependency-management' version '1.1.6' } - + repositories { mavenCentral() } - + dependencies { implementation 'javax.servlet:javax.servlet-api:4.0.1' implementation 'org.apache.activemq:activemq-client-jakarta' @@ -507,11 +546,11 @@ void doesNotPinPropertyManagedVersions() { id 'org.springframework.boot' version '2.5.14' id 'io.spring.dependency-management' version '1.0.11.RELEASE' } - + repositories { mavenCentral() } - + dependencies { runtimeOnly 'mysql:mysql-connector-java' } @@ -522,11 +561,11 @@ void doesNotPinPropertyManagedVersions() { id 'org.springframework.boot' version '2.5.15' id 'io.spring.dependency-management' version '1.0.11.RELEASE' } - + repositories { mavenCentral() } - + dependencies { runtimeOnly 'mysql:mysql-connector-java' }