Skip to content

Commit

Permalink
Match maven's handling of obsolete poms by refusing resolve their dep…
Browse files Browse the repository at this point in the history
…endencies.
  • Loading branch information
sambsnyd committed May 18, 2024
1 parent ed6f97a commit 7390cc1
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 33 deletions.
1 change: 1 addition & 0 deletions rewrite-maven/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ dependencies {
testImplementation("com.squareup.okio:okio-jvm:3.0.0")
testImplementation("org.mapdb:mapdb:latest.release")
testImplementation("guru.nidi:graphviz-java:latest.release")
compileOnly("com.google.errorprone:error_prone_core:latest.release")

testRuntimeOnly("org.mapdb:mapdb:latest.release")
testRuntimeOnly(project(":rewrite-java-17"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.NonFinal;
import org.openrewrite.internal.StringUtils;
import org.openrewrite.internal.lang.NonNull;
import org.openrewrite.internal.lang.Nullable;
import org.openrewrite.maven.tree.*;
Expand All @@ -49,6 +50,11 @@
@Data
@XmlRootElement(name = "project")
public class RawPom {

// Obsolete field supplanted by the "modelVersion" field in modern poms
@Nullable
String pomVersion;

@Nullable
Parent parent;

Expand All @@ -66,6 +72,10 @@ public class RawPom {
@Nullable
String version;

// Obsolete field supplanted by the "version" field in modern poms
@Nullable
String currentVersion;

@EqualsAndHashCode.Include
@ToString.Include
@Nullable
Expand Down Expand Up @@ -330,35 +340,72 @@ public String getGroupId() {

@Nullable
public String getVersion() {
return version == null && parent != null ? parent.getVersion() : version;
if(version == null) {
if(currentVersion == null) {
if(parent == null) {
return null;
} else {
return parent.getVersion();
}
} else {
return currentVersion;
}
}
return version;
}


public Pom toPom(@Nullable Path inputPath, @Nullable MavenRepository repo) {
org.openrewrite.maven.tree.Parent parent = getParent() == null ? null : new org.openrewrite.maven.tree.Parent(new GroupArtifactVersion(
getParent().getGroupId(), getParent().getArtifactId(),
getParent().getVersion()), getParent().getRelativePath());

return new Pom(
inputPath,
repo,
parent,
new ResolvedGroupArtifactVersion(
Pom.PomBuilder builder = Pom.builder()
.sourcePath(inputPath)
.repository(repo)
.parent(parent)
.gav(new ResolvedGroupArtifactVersion(
repo == null ? null : repo.getUri(),
Objects.requireNonNull(getGroupId()),
artifactId,
Objects.requireNonNull(getVersion()),
null),
name,
getPackaging(),
getProperties() == null ? emptyMap() : getProperties(),
mapDependencyManagement(getDependencyManagement()),
mapRequestedDependencies(getDependencies()),
mapRepositories(getRepositories()),
mapLicenses(getLicenses()),
mapProfiles(getProfiles()),
mapPlugins((build != null) ? build.getPlugins() : null),
mapPlugins((build != null && build.getPluginManagement() != null) ? build.getPluginManagement().getPlugins() : null)
);
null))
.name(name)
.obsoletePomVersion(pomVersion)
.packaging(packaging)
.properties(getProperties() == null ? emptyMap() : getProperties())
.licenses(mapLicenses(getLicenses()))
.profiles(mapProfiles(getProfiles()));
if(StringUtils.isBlank(pomVersion)) {
builder.dependencies(mapRequestedDependencies(getDependencies()))
.dependencyManagement(mapDependencyManagement(getDependencyManagement()))
.repositories(mapRepositories(getRepositories()))
.plugins(mapPlugins((build != null) ? build.getPlugins() : null))
.pluginManagement(mapPlugins((build != null && build.getPluginManagement() != null) ? build.getPluginManagement().getPlugins() : null));
}
return builder.build();
// return new Pom(
// inputPath,
// repo,
// parent,
// new ResolvedGroupArtifactVersion(
// repo == null ? null : repo.getUri(),
// Objects.requireNonNull(getGroupId()),
// artifactId,
// Objects.requireNonNull(getVersion()),
// null),
// name,
// null,
// getPackaging(),
// getProperties() == null ? emptyMap() : getProperties(),
// mapDependencyManagement(getDependencyManagement()),
// mapRequestedDependencies(getDependencies()),
// mapRepositories(getRepositories()),
// mapLicenses(getLicenses()),
// mapProfiles(getProfiles()),
// mapPlugins((build != null) ? build.getPlugins() : null),
// mapPlugins((build != null && build.getPluginManagement() != null) ? build.getPluginManagement().getPlugins() : null)
// );
}

private List<org.openrewrite.maven.tree.License> mapLicenses(@Nullable Licenses rawLicenses) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ public static int getModelVersion() {

ResolvedGroupArtifactVersion gav;

/**
* Old Maven Poms had a "pomVersion" field which was replaced by "modelVersion" in newer versions of Maven.
* When Maven encounters a pom with this field, it refuses to resolve its dependencies.
* We keep track of this field so that we can match Maven's behavior.
*/
@Nullable
String obsoletePomVersion;

@Nullable
String name;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,7 @@
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.Builder;
import lombok.Getter;
import lombok.Value;
import lombok.With;
import lombok.*;
import lombok.experimental.NonFinal;
import org.openrewrite.ExecutionContext;
import org.openrewrite.internal.ListUtils;
Expand Down Expand Up @@ -58,10 +55,9 @@ public class ResolvedPom {
public static final PropertyPlaceholderHelper placeholderHelper = new PropertyPlaceholderHelper("${", "}", null);

// https://maven.apache.org/ref/3.6.3/maven-model-builder/super-pom.html
private static final ResolvedPom SUPER_POM = new ResolvedPom(
new Pom(null, null, null, null, null, null, emptyMap(), emptyList(), emptyList(), singletonList(MavenRepository.MAVEN_CENTRAL), emptyList(), emptyList(), null, null),
emptyList()
);
private static final ResolvedPom SUPER_POM = ResolvedPom.builder()
.repositories(singletonList(MavenRepository.MAVEN_CENTRAL))
.build();

@With
Pom requested;
Expand Down Expand Up @@ -159,6 +155,11 @@ private static class UniqueDependencyKey {
*/
@SuppressWarnings("DuplicatedCode")
public ResolvedPom resolve(ExecutionContext ctx, MavenPomDownloader downloader) throws MavenDownloadingException {
// If this resolved pom represents an obsolete pom format, refuse to resolve in same as Maven itself would
if(requested.getObsoletePomVersion() != null) {
return this;
}

ResolvedPom resolved = new ResolvedPom(
requested,
activeProfiles,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import org.openrewrite.maven.cache.InMemoryMavenPomCache;
import org.openrewrite.maven.table.MavenMetadataFailures;
import org.openrewrite.maven.tree.MavenRepository;
import org.openrewrite.maven.tree.MavenResolutionResult;
import org.openrewrite.maven.tree.Scope;
import org.openrewrite.test.RewriteTest;
import org.openrewrite.xml.tree.Xml;

Expand Down Expand Up @@ -120,7 +122,7 @@ void unresolvableParent() { // Dad said he was heading to the corner store for c
}

@Test
void unresolvableTransitiveDependency(@TempDir Path localRepository) throws IOException {
void unresolvableTransitiveDependencyDueToInvalidPom(@TempDir Path localRepository) throws IOException {
// it's hard to simulate a transitive dependency failure since Maven Central validates
// transitive dependency resolvability on publishing.
//
Expand Down Expand Up @@ -281,6 +283,63 @@ void unreachableRepository() {
);
}

@Test
void oldPomVersionNoDependencyResolution() {
rewriteRun(
pomXml(
"""
<project>
<pomVersion>3</pomVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<dependencies>
<!-- Dependency resolution is not attempted since this pom has a "pomVersion" field -->
<dependency>
<groupId>org.whatever</groupId>
<artifactId>doesnotexist</artifactId>
<version>8.0</version>
</dependency>
</dependencies>
</project>
""")
);
}

@Test
void unresolvableTransitiveDependencyDueToInvalidPom() {
rewriteRun(
pomXml(
"""
<project>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<dependencies>
<dependency>
<!-- staxex has a pom with an obsolete format, its dependencies should NOT be resolved -->
<groupId>org.jvnet.staxex</groupId>
<artifactId>stax-ex</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>
""",
spec -> spec.afterRecipe(pom ->
{
assertThat(pom.getMarkers().findFirst(MavenResolutionResult.class))
.isPresent()
.get()
.extracting(mrr -> mrr.getDependencies().get(Scope.Compile))
.matches(deps -> deps.size() == 1)
.extracting(deps -> deps.get(0))
.matches(dep -> dep.getGroupId().equals("org.jvnet.staxex") &&
dep.getArtifactId().equals("stax-ex") &&
dep.getVersion().equals("1.0"));
}))
);
}

private Recipe updateModel() {
return toRecipe(() -> new MavenIsoVisitor<>() {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,18 +171,18 @@ void deserializePom() throws JsonProcessingException {
String pomString = """
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
</parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<packaging>jar</packaging>
<dependencyManagement>
<dependencies>
<dependency>
Expand All @@ -194,7 +194,7 @@ void deserializePom() throws JsonProcessingException {
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
Expand All @@ -209,7 +209,7 @@ void deserializePom() throws JsonProcessingException {
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
Expand Down Expand Up @@ -382,7 +382,7 @@ void deserializePom() throws JsonProcessingException {
</plugins>
</pluginManagement>
</build>
</profile>
</profiles>
</project>
Expand Down
6 changes: 6 additions & 0 deletions rewrite-xml/src/main/java/org/openrewrite/xml/tree/Xml.java
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,12 @@ public static Xml.Tag build(@Language("xml") String tagSource) {
}

public Tag withName(String name) {
if(!name.equals(name.trim())) {
throw new IllegalArgumentException("Tag name must not contain leading or trailing whitespace");
}
if(this.name.equals(name)) {
return this;
}
return new Tag(id, prefixUnsafe, markers, name, attributes, content,
closing == null ? null : closing.withName(name),
beforeTagDelimiterPrefix);
Expand Down

0 comments on commit 7390cc1

Please sign in to comment.