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
Expand Up @@ -304,8 +304,7 @@ public Xml.Document visitDocument(Xml.Document document, ExecutionContext ctx) {
Pom updatedPom = mrr.getPom().getRequested().withParent(updatedParentRef);
ResolvedPom updatedResolvedPom = mrr.getPom()
.withRequested(updatedPom)
.resolve(ctx, new MavenPomDownloader(
mrr.getProjectPoms(), ctx, mrr.getMavenSettings(), mrr.getActiveProfiles()));
.resolve(ctx, MavenPomDownloader.forResolutionResult(mrr, ctx));
acc.updatedRootMarker = mrr.withPom(updatedResolvedPom);
}
} catch (MavenDownloadingException e) {
Expand Down Expand Up @@ -409,7 +408,7 @@ public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) {
}

// Retain managed versions from the old parent that are not managed in the new parent
MavenPomDownloader mpd = new MavenPomDownloader(mrr.getProjectPoms(), ctx, mrr.getMavenSettings(), mrr.getActiveProfiles());
MavenPomDownloader mpd = MavenPomDownloader.forResolutionResult(mrr, ctx);
ResolvedPom oldParent = mpd.download(new GroupArtifactVersion(currentGroupId, currentArtifactId, oldVersion), null, resolvedPom, resolvedPom.getRepositories())
.resolve(emptyList(), mpd, ctx);
ResolvedPom newParent = mpd.download(new GroupArtifactVersion(targetGroupId, targetArtifactId, targetVersion.get()), null, resolvedPom, resolvedPom.getRepositories())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ private boolean matchesVersion(ResolvedManagedDependency d, ExecutionContext ctx
}
try {
GroupArtifactVersion parentGav = mrr.getPom().getRequested().getParent().getGav();
MavenPomDownloader mpd = new MavenPomDownloader(mrr.getProjectPoms(), ctx, mrr.getMavenSettings(), mrr.getActiveProfiles());
MavenPomDownloader mpd = MavenPomDownloader.forResolutionResult(mrr, ctx);
ResolvedPom parentPom = mpd.download(parentGav, null, mrr.getPom(), mrr.getPom().getRepositories())
.resolve(emptyList(), mpd, ctx);
ResolvedManagedDependency parentManagedVersion = parentPom.getDependencyManagement().stream()
Expand Down Expand Up @@ -320,7 +320,7 @@ private boolean matchesManagedVersion(Plugin p, ExecutionContext ctx) {
}
try {
GroupArtifactVersion parentGav = mrr.getPom().getRequested().getParent().getGav();
MavenPomDownloader mpd = new MavenPomDownloader(mrr.getProjectPoms(), ctx, mrr.getMavenSettings(), mrr.getActiveProfiles());
MavenPomDownloader mpd = MavenPomDownloader.forResolutionResult(mrr, ctx);
ResolvedPom parentPom = mpd.download(parentGav, null, mrr.getPom(), mrr.getPom().getRepositories())
.resolve(emptyList(), mpd, ctx);
return parentPom.getPluginManagement().stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,7 @@ private boolean hasMatchingValue(Xml.Tag tag, ExecutionContext ctx) {
MavenResolutionResult mrr = getResolutionResult();
Map<String, String> parentProperties;
if (mrr.getParent() == null) {
MavenPomDownloader downloader = new MavenPomDownloader(
mrr.getProjectPoms(),
ctx,
mrr.getMavenSettings(),
mrr.getActiveProfiles());
MavenPomDownloader downloader = MavenPomDownloader.forResolutionResult(mrr, ctx);
try {
// Resolve the external parent POM properties
parentProperties = mrr
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,7 @@ private boolean isAncestor(MavenResolutionResult project, ResolvedGroupArtifactV

private boolean parentHasProperty(MavenResolutionResult resolutionResult, String propertyName,
ExecutionContext ctx) {
MavenPomDownloader downloader = new MavenPomDownloader(resolutionResult.getProjectPoms(), ctx,
resolutionResult.getMavenSettings(), resolutionResult.getActiveProfiles());
MavenPomDownloader downloader = MavenPomDownloader.forResolutionResult(resolutionResult, ctx);
try {
ResolvedPom resolvedBarePom = resolutionResult.getPom().getRequested()
.withProperties(emptyMap())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,8 @@ private static void markModulesRecursive(ExecutionContext ctx, MavenResolutionRe
}

private MavenResolutionResult updateResult(ExecutionContext ctx, MavenResolutionResult resolutionResult, Map<Path, Pom> projectPoms) throws MavenDownloadingExceptions {
MavenPomDownloader downloader = new MavenPomDownloader(projectPoms, ctx, getResolutionResult().getMavenSettings(),
MavenPomDownloader downloader = new MavenPomDownloader(projectPoms, ctx,
MavenExecutionContextView.view(ctx).effectiveSettings(getResolutionResult()),
getResolutionResult().getActiveProfiles());

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ public class MavenPomDownloader {
private boolean addLocalRepository;

/**
* Prefer {@link #forResolutionResult(MavenResolutionResult, ExecutionContext)} when resolving on
* behalf of an already-parsed source: settings passed here replace, rather than combine with, the
* settings on the execution context, so passing a resolution result's settings directly discards
* run-time configuration such as mirrors.
*
* @param projectPoms Other POMs in this project.
* @param ctx The execution context, which potentially contain Maven settings customization
* and {@link HttpSender} customization.
Expand All @@ -108,6 +113,17 @@ public MavenPomDownloader(Map<Path, Pom> projectPoms,
this.activeProfiles = activeProfiles;
}

/**
* A downloader resolving further poms and metadata on behalf of a source that was already parsed,
* combining the Maven settings carried by its {@link MavenResolutionResult} with those on the execution
* context, so that both parse-time configuration (e.g. mirrors captured in the LST) and run-time
* configuration are honored.
*/
public static MavenPomDownloader forResolutionResult(MavenResolutionResult mrr, ExecutionContext ctx) {
return new MavenPomDownloader(mrr.getProjectPoms(), ctx,
MavenExecutionContextView.view(ctx).effectiveSettings(mrr), mrr.getActiveProfiles());
}

/**
* A MavenPomDownloader for non-maven contexts where there are no project poms or assumption that maven central
* is implicitly added as a repository. In a Maven contexts, a non-empty projectPoms should be specified to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,10 @@ public Xml.Document visitDocument(Xml.Document document, ExecutionContext ctx) {
for (MavenRepository repository : mrr.getPom().getRepositories()) {
repositories.put(repository.getUri(), repository);
}
for (MavenRepository repository : MavenExecutionContextView.view(ctx)
MavenExecutionContextView mctx = MavenExecutionContextView.view(ctx);
for (MavenRepository repository : mctx
.getRepositories(
mrr.getMavenSettings(),
mctx.effectiveSettings(mrr),
StreamSupport.stream(mrr.getPom().getActiveProfiles().spliterator(), false)
.collect(toList())
)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) {
}

MavenResolutionResult mrr = getResolutionResult();
MavenPomDownloader mpd = new MavenPomDownloader(mrr.getProjectPoms(), ctx, mrr.getMavenSettings(), mrr.getActiveProfiles());
MavenPomDownloader mpd = MavenPomDownloader.forResolutionResult(mrr, ctx);

Parent ancestor = mrr.getPom().getRequested().getParent();
String relativePath = tag.getChildValue("relativePath").orElse(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static java.util.Collections.emptyMap;
import static org.openrewrite.internal.StringUtils.matchesGlob;
Expand Down Expand Up @@ -87,12 +86,7 @@ public class MavenDependency implements Trait<Xml.Tag> {
MavenMetadata mavenMetadata;
try {
mavenMetadata = metadataFailures.insertRows(ctx, () -> new MavenPomDownloader(
emptyMap(), ctx,
settings,
Optional.ofNullable(settings)
.map(MavenSettings::getActiveProfiles)
.map(MavenSettings.ActiveProfiles::getActiveProfiles)
.orElse(null)
emptyMap(), ctx, settings, mrr.getActiveProfiles()
).downloadMetadata(new GroupArtifact(groupId, artifactId), null, mrr.getPom().getRepositories()));
} catch (NumberFormatException e) {
// this can happen when we encounter exotic, non-semver version numbers
Expand All @@ -115,9 +109,9 @@ public class MavenDependency implements Trait<Xml.Tag> {
// This is a best effort attempt to see if the pom is there anyway, in spite of the
// fact that it's not in the metadata. Usually it won't be, only in situations like the
// MapR repository mentioned in the comment above will it be.
Pom pom = new MavenPomDownloader(emptyMap(), ctx,
mrr.getMavenSettings(), mrr.getActiveProfiles()).download(new GroupArtifactVersion(groupId, artifactId, ((ExactVersion) versionComparator).getVersion()),
null, null, mrr.getPom().getRepositories());
Pom pom = new MavenPomDownloader(emptyMap(), ctx, settings, mrr.getActiveProfiles())
.download(new GroupArtifactVersion(groupId, artifactId, exactVersion),
null, null, mrr.getPom().getRepositories());
if (pom.getGav().getVersion().equals(exactVersion) &&
!exactVersion.equals(finalVersion) &&
versionComparator.compare(finalVersion, finalVersion, exactVersion) <= 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public static Set<String> filterPropertiesWithOverlapInParents(
ResolvedPom currentResolved = current.getPom();
remainingProperties = filterPropertiesWithOverlapInDependencies(remainingProperties, groupId, artifactId, currentResolved.getRequested(), currentResolved, configuredToChangeManagedDependency);
}
MavenPomDownloader downloader = new MavenPomDownloader(current.getProjectPoms(), ctx);
MavenPomDownloader downloader = MavenPomDownloader.forResolutionResult(current, ctx);
ResolvedPom currentResolved = current.getPom();
while (currentResolved.getRequested().getParent() != null) {
if (remainingProperties.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@
import org.openrewrite.InMemoryExecutionContext;
import org.openrewrite.Parser;
import org.openrewrite.Recipe;
import org.openrewrite.Tree;
import org.openrewrite.ipc.http.HttpSender;
import org.openrewrite.maven.internal.MavenPomDownloader;
import org.openrewrite.maven.search.ParentPomInsight;
import org.openrewrite.maven.table.MavenMetadataFailures;
import org.openrewrite.maven.trait.MavenDependency;
import org.openrewrite.maven.tree.GroupArtifact;
Expand Down Expand Up @@ -71,6 +73,30 @@ class MavenCentralMirrorTest {
</project>
""";

@Language("xml")
private static final String POM_WITH_PARENT = """
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.example.hermetic</groupId>
<artifactId>hermetic-parent</artifactId>
<version>1</version>
</parent>
<artifactId>my-app</artifactId>
</project>
""";

@Language("xml")
private static final String PARENT_POM = """
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.example.hermetic</groupId>
<artifactId>hermetic-parent</artifactId>
<version>1</version>
<packaging>pom</packaging>
</project>
""";

@Language("xml")
private static final String METADATA = """
<metadata>
Expand Down Expand Up @@ -98,7 +124,14 @@ static class RecordingHttpSender implements HttpSender {
public Response send(Request request) {
String url = request.getUrl().toString();
requestedUrls.add(url);
byte[] body = url.endsWith("maven-metadata.xml") ? METADATA.getBytes(StandardCharsets.UTF_8) : new byte[0];
byte[] body;
if (url.endsWith("maven-metadata.xml")) {
body = METADATA.getBytes(StandardCharsets.UTF_8);
} else if (url.endsWith("hermetic-parent-1.pom")) {
body = PARENT_POM.getBytes(StandardCharsets.UTF_8);
} else {
body = new byte[0];
}
return new Response(200, new ByteArrayInputStream(body), () -> {
});
}
Expand Down Expand Up @@ -130,6 +163,23 @@ void lstMirrorHonoredWhenContextHasNoSettings() throws MavenDownloadingException
assertOnlyMirrorContacted(ctx);
}

@Test
void recipeParentResolutionHonorsContextMirror() {
// The inverse direction: the LST was produced without any mirror, and the mirror is supplied
// on the execution context at recipe run time. A recipe resolving parent poms must route that
// traffic through the context's mirror rather than the settings captured in the LST.
Xml.Document pom = parsePomWithParent(settingsWithServerCredentialsOnly());
ExecutionContext ctx = runContext();
MavenExecutionContextView.view(ctx).setMavenSettings(settingsWithMirror("central"));

Tree after = new ParentPomInsight("com.example.nonexistent", "*", null, null).getVisitor().visit(pom, ctx);

assertThat(after)
.as("parent resolution must succeed (a download failure would attach a warning markup)")
.isSameAs(pom);
assertOnlyMirrorContacted(ctx, "hermetic-parent-1.pom");
}

@Test
void implicitlyAddedCentralRedirectedToMirror() throws MavenDownloadingException {
// Even when no repository is supplied at all, the downloader implicitly adds Maven Central;
Expand Down Expand Up @@ -199,6 +249,13 @@ private static MavenResolutionResult parsePomWith(MavenSettings settings) {
return mrr;
}

private static Xml.Document parsePomWithParent(MavenSettings settings) {
return (Xml.Document) MavenParser.builder().build()
.parse(parseContext(settings), POM_WITH_PARENT)
.findFirst()
.orElseThrow();
}

private static ExecutionContext parseContext(MavenSettings settings) {
ExecutionContext parseCtx = runContext();
MavenExecutionContextView.view(parseCtx).setMavenSettings(settings);
Expand Down Expand Up @@ -229,12 +286,16 @@ private static InMemoryExecutionContext throwingContext() {
}

private static void assertOnlyMirrorContacted(ExecutionContext ctx) {
assertOnlyMirrorContacted(ctx, "maven-metadata.xml");
}

private static void assertOnlyMirrorContacted(ExecutionContext ctx, String expectedSuffix) {
RecordingHttpSender sender = (RecordingHttpSender)
HttpSenderExecutionContextView.view(ctx).getHttpSender();
assertThat(sender.requestedUrls)
.as("all resolution traffic must be redirected to the mirror")
.allSatisfy(url -> assertThat(url).startsWith(MIRROR_URL))
.as("at least one metadata request must have reached the mirror")
.anySatisfy(url -> assertThat(url).endsWith("maven-metadata.xml"));
.as("the request for %s must have reached the mirror", expectedSuffix)
.anySatisfy(url -> assertThat(url).endsWith(expectedSuffix));
}
}