Skip to content
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 @@ -138,6 +138,12 @@ private List<Statement> addPluginManagementRepos(List<Statement> statements, J p
if (mapped != statements) {
return mapped;
}
// Check if pluginManagement exists but no change was needed (repo already present)
for (Statement s : statements) {
if (unwrapMethodCall(s, "pluginManagement") != null) {
return statements;
}
}
// No existing pluginManagement found — insert after any leading imports
Statement pluginManagementStatement = pluginManagement instanceof J.Block ?
((J.Block) pluginManagement).getStatements().get(0) :
Expand Down Expand Up @@ -190,6 +196,11 @@ private Statement addRepoToRepositoriesBlock(Statement statement, J pluginManage
return statement;
}
J.MethodInvocation repoToAdd = extractRepository(pluginManagement);

if (repoAlreadyExists(repos, repoToAdd.getSimpleName())) {
return statement;
}

J.MethodInvocation m2 = repos.withArguments(ListUtils.mapFirst(repos.getArguments(), arg2 -> {
if (!(arg2 instanceof J.Lambda) || !(((J.Lambda) arg2).getBody() instanceof J.Block)) {
return arg2;
Expand All @@ -208,6 +219,23 @@ private Statement addRepoToRepositoriesBlock(Statement statement, J pluginManage
return rewrap(statement, m2);
}

// Name-based fallback for when MethodMatcher fails due to incorrect type attribution (e.g. rewrite-kotlin)
private boolean repoAlreadyExists(J.MethodInvocation repos, String repoName) {
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 believe that this fails for any non first party named repository. As an example, multiple maven {} are allowed and this would improperly match on those only allowing for there to be one.

I think the root cause issue here is improper matching in FindRepository which allows us to get this far. If we need to we do have the repositories available as elements in the GradleProject marker that we could utilize as well for match selection much like we do for FindGradleProject.

if (repos.getArguments().isEmpty() || !(repos.getArguments().get(0) instanceof J.Lambda)) {
return false;
}
J.Lambda lambda = (J.Lambda) repos.getArguments().get(0);
if (!(lambda.getBody() instanceof J.Block)) {
return false;
}
for (Statement s : ((J.Block) lambda.getBody()).getStatements()) {
if (unwrapMethodCall(s, repoName) != null) {
return true;
}
}
return false;
}

private <T extends JavaSourceFile> J generatePluginManagementBlock(Class<T> compilationUnitClass, Function<T, J> methodExtractor, ExecutionContext ctx) {
String code;
if (url == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@

import org.junit.jupiter.api.Test;
import org.openrewrite.DocumentExample;
import org.openrewrite.SourceFile;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaType;
import org.openrewrite.test.RewriteTest;

import static org.openrewrite.gradle.Assertions.settingsGradle;
Expand Down Expand Up @@ -584,6 +588,60 @@ void noPluginManagementBlockWithBuildCacheKts() {
);
}

/**
* Simulate platform behavior where KTS-parsed settings.gradle.kts has incomplete type
* attribution — method types have a wrong declaring type instead of being null.
*/
@SuppressWarnings("unchecked")
private static <T extends SourceFile> T corruptMethodTypes(T sourceFile) {
JavaType.FullyQualified wrongType = JavaType.ShallowClass.build("kotlin.Unit");
return (T) new JavaIsoVisitor<Integer>() {
@Override
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Integer p) {
J.MethodInvocation m = super.visitMethodInvocation(method, p);
if (m.getMethodType() != null) {
return m.withMethodType(m.getMethodType().withDeclaringType(wrongType));
}
return m;
}
}.visitNonNull(sourceFile, 0);
}

@Test
void skipWhenExistsGradlePluginPortalKtsWithoutTypeAttribution() {
rewriteRun(
spec -> spec.recipe(new AddSettingsPluginRepository("gradlePluginPortal", null)),
settingsGradleKts(
"""
pluginManagement {
repositories {
gradlePluginPortal()
}
}
""",
spec -> spec.mapBeforeRecipe(AddSettingsPluginRepositoryTest::corruptMethodTypes)
)
);
}

@Test
void skipWhenExistsGradlePluginPortalWithOtherReposKtsWithoutTypeAttribution() {
rewriteRun(
spec -> spec.recipe(new AddSettingsPluginRepository("gradlePluginPortal", null)),
settingsGradleKts(
"""
pluginManagement {
repositories {
mavenLocal()
gradlePluginPortal()
}
}
""",
spec -> spec.mapBeforeRecipe(AddSettingsPluginRepositoryTest::corruptMethodTypes)
)
);
}

@Test
void addToExistingPluginManagementWithPluginsBlockKts() {
rewriteRun(
Expand Down