Skip to content
Draft
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
@@ -0,0 +1,82 @@
/*
* Copyright 2026 the original author or authors.
* <p>
* Licensed under the Moderne Source Available License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* https://docs.moderne.io/licensing/moderne-source-available-license
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openrewrite.java.flyway;

import lombok.EqualsAndHashCode;
import lombok.Value;
import org.jspecify.annotations.Nullable;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Option;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.maven.ChangeDependencyScope;
import org.openrewrite.maven.MavenIsoVisitor;
import org.openrewrite.xml.tree.Xml;

@Value
@EqualsAndHashCode(callSuper = false)
public class AlignFlywayModuleScopeWithFlywayCore extends Recipe {

@Option(displayName = "Flyway module artifactId",
description = "ArtifactId of the Flyway database module to align with `flyway-core`.",
example = "flyway-database-postgresql")
String artifactId;

String displayName = "Align Flyway module scope with flyway-core";

String description = "Ensures Flyway database modules keep the same declared Maven scope as `flyway-core` " +
"when migrations add or touch those dependencies.";

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new MavenIsoVisitor<ExecutionContext>() {
@Override
public Xml.Document visitDocument(Xml.Document document, ExecutionContext ctx) {
Xml.Document d = super.visitDocument(document, ctx);
String flywayCoreScope = findDeclaredScope(d.getRoot(), "org.flywaydb", "flyway-core");
if (!"test".equals(flywayCoreScope)) {
return d;
}
return (Xml.Document) new ChangeDependencyScope("org.flywaydb", artifactId, "test").getVisitor().visitNonNull(d, ctx);
}

private @Nullable String findDeclaredScope(Xml.Tag tag, String groupId, String artifactId) {
if (isDependency(groupId, artifactId, tag)) {
return tag.getChildValue("scope").orElse(null);
}
java.util.List<?> content = tag.getContent();
if (content == null) {
return null;
}
for (Object child : content) {
if (child instanceof Xml.Tag) {
String scope = findDeclaredScope((Xml.Tag) child, groupId, artifactId);
if (scope != null || isDependency(groupId, artifactId, (Xml.Tag) child)) {
return scope;
}
}
}
return null;
}

private boolean isDependency(String groupId, String artifactId, Xml.Tag tag) {
return "dependency".equals(tag.getName()) &&
groupId.equals(tag.getChildValue("groupId").orElse(null)) &&
artifactId.equals(tag.getChildValue("artifactId").orElse(null));
}
};
}
}
8 changes: 8 additions & 0 deletions src/main/resources/META-INF/rewrite/flyway-10.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,17 @@ preconditions:
- org.openrewrite.Singleton
recipeList:
- org.openrewrite.java.flyway.AddFlywayModulePostgreSQL
- org.openrewrite.java.flyway.AlignFlywayModuleScopeWithFlywayCore:
artifactId: flyway-database-postgresql
- org.openrewrite.java.flyway.AddFlywayModuleMySQL
- org.openrewrite.java.flyway.AlignFlywayModuleScopeWithFlywayCore:
artifactId: flyway-mysql
- org.openrewrite.java.flyway.AddFlywayModuleOracle
- org.openrewrite.java.flyway.AlignFlywayModuleScopeWithFlywayCore:
artifactId: flyway-database-oracle
- org.openrewrite.java.flyway.AddFlywayModuleSqlServer
- org.openrewrite.java.flyway.AlignFlywayModuleScopeWithFlywayCore:
artifactId: flyway-sqlserver
---
type: specs.openrewrite.org/v1beta/recipe
name: org.openrewrite.java.flyway.AddFlywayModulePostgreSQL
Expand Down
182 changes: 182 additions & 0 deletions src/test/java/org/openrewrite/java/flyway/MigrateToFlyway10Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import org.junit.jupiter.api.Test;
import org.openrewrite.DocumentExample;
import org.openrewrite.Issue;
import org.openrewrite.test.RecipeSpec;
import org.openrewrite.test.RewriteTest;

Expand Down Expand Up @@ -284,4 +285,185 @@ void addSqlServerDependency() {
)
);
}

@Issue("https://github.com/openrewrite/rewrite-spring/issues/1052")
@Test
void addPostgresDependencyWithTestScope() {
assertFlywayModuleAddedWithTestScope(
"org.postgresql",
"postgresql",
"flyway-database-postgresql"
);
}

@Issue("https://github.com/openrewrite/rewrite-spring/issues/1052")
@Test
void preserveExistingPostgresDependencyTestScope() {
rewriteRun(
//language=xml
pomXml(
pom(
"<project>",
"\t<modelVersion>4.0.0</modelVersion>",
"\t<parent>",
"\t\t<groupId>org.springframework.boot</groupId>",
"\t\t<artifactId>spring-boot-starter-parent</artifactId>",
"\t\t<version>3.3.12</version>",
"\t\t<relativePath/>",
"\t</parent>",
"\t<groupId>com.example</groupId>",
"\t<artifactId>demo</artifactId>",
"\t<version>0.0.1-SNAPSHOT</version>",
"\t<dependencies>",
"\t\t<dependency>",
"\t\t\t<groupId>org.flywaydb</groupId>",
"\t\t\t<artifactId>flyway-core</artifactId>",
"\t\t\t<scope>test</scope>",
"\t\t</dependency>",
"\t\t<dependency>",
"\t\t\t<groupId>org.flywaydb</groupId>",
"\t\t\t<artifactId>flyway-database-postgresql</artifactId>",
"\t\t\t<scope>test</scope>",
"\t\t</dependency>",
"\t\t<dependency>",
"\t\t\t<groupId>org.postgresql</groupId>",
"\t\t\t<artifactId>postgresql</artifactId>",
"\t\t\t<scope>runtime</scope>",
"\t\t</dependency>",
"\t</dependencies>",
"</project>"
),
pom(
"<project>",
"\t<modelVersion>4.0.0</modelVersion>",
"\t<parent>",
"\t\t<groupId>org.springframework.boot</groupId>",
"\t\t<artifactId>spring-boot-starter-parent</artifactId>",
"\t\t<version>3.3.12</version>",
"\t\t<relativePath/>",
"\t</parent>",
"\t<groupId>com.example</groupId>",
"\t<artifactId>demo</artifactId>",
"\t<version>0.0.1-SNAPSHOT</version>",
"\t<dependencies>",
"\t\t<dependency>",
"\t\t\t<groupId>org.flywaydb</groupId>",
"\t\t\t<artifactId>flyway-core</artifactId>",
"\t\t\t<scope>test</scope>",
"\t\t</dependency>",
"\t\t<dependency>",
"\t\t\t<groupId>org.flywaydb</groupId>",
"\t\t\t<artifactId>flyway-database-postgresql</artifactId>",
"\t\t\t<scope>test</scope>",
"\t\t</dependency>",
"\t\t<dependency>",
"\t\t\t<groupId>org.postgresql</groupId>",
"\t\t\t<artifactId>postgresql</artifactId>",
"\t\t\t<scope>runtime</scope>",
"\t\t</dependency>",
"\t</dependencies>",
"</project>"
)
)
);
}

@Issue("https://github.com/openrewrite/rewrite-spring/issues/1052")
@Test
void addMySQLDependencyWithTestScope() {
assertFlywayModuleAddedWithTestScope(
"com.mysql",
"mysql-connector-j",
"flyway-mysql"
);
}

@Issue("https://github.com/openrewrite/rewrite-spring/issues/1052")
@Test
void addOracleDependencyWithTestScope() {
assertFlywayModuleAddedWithTestScope(
"com.oracle.database.jdbc",
"ojdbc11",
"flyway-database-oracle"
);
}

@Issue("https://github.com/openrewrite/rewrite-spring/issues/1052")
@Test
void addSqlServerDependencyWithTestScope() {
assertFlywayModuleAddedWithTestScope(
"com.microsoft.sqlserver",
"mssql-jdbc",
"flyway-sqlserver"
);
}

private void assertFlywayModuleAddedWithTestScope(String databaseGroupId, String databaseArtifactId, String flywayModuleArtifactId) {
rewriteRun(
//language=xml
pomXml(
pom(
"<project>",
"\t<modelVersion>4.0.0</modelVersion>",
"\t<parent>",
"\t\t<groupId>org.springframework.boot</groupId>",
"\t\t<artifactId>spring-boot-starter-parent</artifactId>",
"\t\t<version>3.3.12</version>",
"\t\t<relativePath/>",
"\t</parent>",
"\t<groupId>com.example</groupId>",
"\t<artifactId>demo</artifactId>",
"\t<version>0.0.1-SNAPSHOT</version>",
"\t<dependencies>",
"\t\t<dependency>",
"\t\t\t<groupId>org.flywaydb</groupId>",
"\t\t\t<artifactId>flyway-core</artifactId>",
"\t\t\t<scope>test</scope>",
"\t\t</dependency>",
"\t\t<dependency>",
("\t\t\t<groupId>%s</groupId>").formatted(databaseGroupId),
("\t\t\t<artifactId>%s</artifactId>").formatted(databaseArtifactId),
"\t\t\t<scope>runtime</scope>",
"\t\t</dependency>",
"\t</dependencies>",
"</project>"
),
pom(
"<project>",
"\t<modelVersion>4.0.0</modelVersion>",
"\t<parent>",
"\t\t<groupId>org.springframework.boot</groupId>",
"\t\t<artifactId>spring-boot-starter-parent</artifactId>",
"\t\t<version>3.3.12</version>",
"\t\t<relativePath/>",
"\t</parent>",
"\t<groupId>com.example</groupId>",
"\t<artifactId>demo</artifactId>",
"\t<version>0.0.1-SNAPSHOT</version>",
"\t<dependencies>",
"\t\t<dependency>",
"\t\t\t<groupId>org.flywaydb</groupId>",
("\t\t\t<artifactId>%s</artifactId>").formatted(flywayModuleArtifactId),
"\t\t\t<scope>test</scope>",
"\t\t</dependency>",
"\t\t<dependency>",
"\t\t\t<groupId>org.flywaydb</groupId>",
"\t\t\t<artifactId>flyway-core</artifactId>",
"\t\t\t<scope>test</scope>",
"\t\t</dependency>",
"\t\t<dependency>",
("\t\t\t<groupId>%s</groupId>").formatted(databaseGroupId),
("\t\t\t<artifactId>%s</artifactId>").formatted(databaseArtifactId),
"\t\t\t<scope>runtime</scope>",
"\t\t</dependency>",
"\t</dependencies>",
"</project>"
)
)
);
}

private static String pom(String... lines) {
return String.join("\n", lines) + "\n";
}
}