Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -56,7 +55,6 @@
@EqualsAndHashCode(callSuper = false)
public class UpgradePluginVersion extends ScanningRecipe<UpgradePluginVersion.DependencyVersionState> {
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);
Expand Down Expand Up @@ -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<?, ExecutionContext> getScanner(DependencyVersionState acc) {

Expand Down Expand Up @@ -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<Expression> 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(effectivePluginIdPattern()).get(getCursor()).orElse(null);
if (plugin == null || plugin.getPluginId() == null) {
return m;
}

String pluginId = plugin.getPluginId();
List<Expression> 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);
Expand All @@ -204,31 +166,23 @@ 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;
acc.pluginIdToNewVersion.put(pluginId, resolvedPluginVersion);
} 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);
Expand Down Expand Up @@ -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(effectivePluginIdPattern()).get(getCursor()).orElse(null);

J.MethodInvocation m = (J.MethodInvocation) super.visitMethodInvocation(method, ctx);
if (!isPluginVersion(getCursor())) {
return m;
}
assert m.getSelect() != null;
List<Expression> 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<Expression> 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<Expression> versionArgs = m.getArguments();
return m.withArguments(ListUtils.map(versionArgs, v -> ChangeStringLiteral.withStringValue(v, resolvedVersion)));
}

Expand Down Expand Up @@ -391,6 +335,11 @@ public J visitVariable(J.VariableDeclarations.NamedVariable variable, ExecutionC
return Preconditions.or(propertiesVisitor, Preconditions.check(Preconditions.or(new IsBuildGradle<>(), new IsSettingsGradle<>()), javaVisitor));
}

private String effectivePluginIdPattern() {
// Translate the short "kotlin" DSL name to the full plugin ID pattern
return "kotlin".equals(pluginIdPattern) ? "org.jetbrains.kotlin.*" : pluginIdPattern;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is necessary or the places where we are doing this aren't correct.

In particular, the trait expands out the Kotlin plugin alias to its full plugin id automatically -- kotlin("jvm") -> org.jetbrains.kotlin.jvm. Since the pluginIdPattern is matching on the effective plugin id, then it stands to reason that if an UpgradePluginVersion is trying to target all Kotlin plugins it should instead be doing a pattern of org.jetbrains.kotlin.* as shown. kotlin standalone doesn't really mean anything from a Gradle standpoint.


private @Nullable String literalValue(Expression expr) {
return new JavaVisitor<AtomicReference<@Nullable String>>() {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 &&
Expand All @@ -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"));
}
Expand Down Expand Up @@ -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) {
Expand Down
Loading