Skip to content

Comments

Add ChangeRepository recipe for Gradle build scripts#6785

Draft
Jenson3210 wants to merge 3 commits intomainfrom
change-gradle-repository
Draft

Add ChangeRepository recipe for Gradle build scripts#6785
Jenson3210 wants to merge 3 commits intomainfrom
change-gradle-repository

Conversation

@Jenson3210
Copy link
Contributor

Summary

  • Adds a new ChangeRepository recipe to replace or remove repository declarations in build.gradle and build.gradle.kts files
  • Enables organizations to standardize repository usage across all projects (e.g. migrate from jcenter to mavenCentral, consolidate internal Nexus URLs)
  • Handles deduplication: if the target repository already exists, removes the old one instead of creating a duplicate

Solution

All four parameters are optional, supporting flexible matching and replacement:

Parameter Description
oldType Match by type (jcenter, maven, etc.). Omit to match any type.
oldUrl Match by URL. Omit to match any URL of the given type.
newType Replacement type. Omit (with no newUrl) to remove the match.
newUrl Replacement URL.

Supported transformations:

  • Named → Named: jcenter()mavenCentral()
  • Named → Custom: jcenter()maven { url = "https://..." }
  • Custom → Named: maven { url = "..." }mavenCentral()
  • Custom → Custom: URL change while keeping the type
  • Remove: match and delete without replacement
  • Both Groovy and Kotlin DSL

Example usage for org-wide uniformity

type: specs.openrewrite.org/v1beta/recipe
name: com.myorg.StandardizeRepositories
recipeList:
  - org.openrewrite.gradle.ChangeRepository:
      oldType: jcenter
      newType: mavenCentral
  - org.openrewrite.gradle.ChangeRepository:
      oldUrl: https://old-nexus.internal.com/releases
      newType: maven
      newUrl: https://artifactory.myorg.com/releases

Test plan

  • 23 tests covering all transformation types, both DSLs, idempotency, deduplication, URL-only matching, and removal mode

Adds a new recipe to replace or remove repository declarations in
build.gradle and build.gradle.kts files, enabling organizations to
standardize repository usage.

Supports all combinations: named-to-named (jcenter to mavenCentral),
named-to-custom-maven, custom-maven-to-named, and URL changes.
Automatically deduplicates when the target repository already exists.
All four parameters (oldType, oldUrl, newType, newUrl) are optional,
allowing matching by type, URL, or both, and either replacing or
removing the matched repository.
When newType is null but newUrl is set, keep the matched repository's
type and only change the URL. Previously this would incorrectly enter
remove mode. Also refactored to use effectiveNewType throughout the
visitor to eliminate null checks on newType.
}

@Test
void removeNamedRepository() {
Copy link
Contributor

Choose a reason for hiding this comment

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

This feels a little weird for a "Change" recipe to be removing entries. We do also already have RemoveRepository, so maybe remove isn't necessary for this recipe?

I think changing to something that is already present is fine to trigger a removal for though, so as to not lead to a duplicate definition.

Comment on lines +42 to +51
@Override
public String getDisplayName() {
return "Change repository";
}

@Override
public String getDescription() {
return "Replace or remove a repository in Gradle build scripts to standardize repository usage across an organization. " +
"When no new type or URL is specified, the matching repository will be removed.";
}
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: For these we should utilize the = syntax that was adopted in other recipes.


@Value
@EqualsAndHashCode(callSuper = false)
public class ChangeRepository extends Recipe {
Copy link
Contributor

Choose a reason for hiding this comment

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

callout: We should add a validation to check that old and new repositories are not the same.

public TreeVisitor<?, ExecutionContext> getVisitor() {
MethodMatcher repoMatcher = new MethodMatcher("org.gradle.api.artifacts.dsl.RepositoryHandler " + (oldType != null ? oldType : "*") + "(..)", true);

return Preconditions.check(new IsBuildGradle<>(), new JavaIsoVisitor<ExecutionContext>() {
Copy link
Contributor

Choose a reason for hiding this comment

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

optional: We have a couple of recipes now that interact with repositories. Should we consider wrapping the discovery portion of this up into a Trait instead?

@Jenson3210
Copy link
Contributor Author

Thanks for the early review @shanman190! Was a draft as I did not look at CC's output before heading into the weekend. Will take this into account when asking him to "do more"! 🙏

@shanman190
Copy link
Contributor

No worries at all; I figured that I'd just write up some comments to help out. 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

2 participants