diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/ChangeParentPom.java b/rewrite-maven/src/main/java/org/openrewrite/maven/ChangeParentPom.java index f6ffeec4700..9db01946bb7 100755 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/ChangeParentPom.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/ChangeParentPom.java @@ -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) { @@ -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()) diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveRedundantDependencyVersions.java b/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveRedundantDependencyVersions.java index 7fc17d1321f..8517df37abc 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveRedundantDependencyVersions.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveRedundantDependencyVersions.java @@ -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() @@ -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() diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveRedundantProperties.java b/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveRedundantProperties.java index c4079177084..2611d7a3ec7 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveRedundantProperties.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveRedundantProperties.java @@ -80,11 +80,7 @@ private boolean hasMatchingValue(Xml.Tag tag, ExecutionContext ctx) { MavenResolutionResult mrr = getResolutionResult(); Map 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 diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveUnusedProperties.java b/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveUnusedProperties.java index 2c8bfdb0446..90e74e515b5 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveUnusedProperties.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveUnusedProperties.java @@ -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()) diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/UpdateMavenModel.java b/rewrite-maven/src/main/java/org/openrewrite/maven/UpdateMavenModel.java index c868b24cab5..9080797a9ee 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/UpdateMavenModel.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/UpdateMavenModel.java @@ -195,7 +195,8 @@ private static void markModulesRecursive(ExecutionContext ctx, MavenResolutionRe } private MavenResolutionResult updateResult(ExecutionContext ctx, MavenResolutionResult resolutionResult, Map 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 { diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/internal/MavenPomDownloader.java b/rewrite-maven/src/main/java/org/openrewrite/maven/internal/MavenPomDownloader.java index c278d0b1450..f38f213e1d9 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/internal/MavenPomDownloader.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/internal/MavenPomDownloader.java @@ -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. @@ -108,6 +113,17 @@ public MavenPomDownloader(Map 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 diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/search/FindRepositoryOrder.java b/rewrite-maven/src/main/java/org/openrewrite/maven/search/FindRepositoryOrder.java index 3a39512c185..8496300212f 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/search/FindRepositoryOrder.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/search/FindRepositoryOrder.java @@ -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()) )) { diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/search/ParentPomInsight.java b/rewrite-maven/src/main/java/org/openrewrite/maven/search/ParentPomInsight.java index d1b0047cf17..584bd86f88c 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/search/ParentPomInsight.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/search/ParentPomInsight.java @@ -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); diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/trait/MavenDependency.java b/rewrite-maven/src/main/java/org/openrewrite/maven/trait/MavenDependency.java index 8460f9ac11b..fdf1626add9 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/trait/MavenDependency.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/trait/MavenDependency.java @@ -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; @@ -87,12 +86,7 @@ public class MavenDependency implements Trait { 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 @@ -115,9 +109,9 @@ public class MavenDependency implements Trait { // 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) { diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/utilities/MavenDependencyPropertyUsageOverlap.java b/rewrite-maven/src/main/java/org/openrewrite/maven/utilities/MavenDependencyPropertyUsageOverlap.java index 1ab82370f38..1aad4bdd8b8 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/utilities/MavenDependencyPropertyUsageOverlap.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/utilities/MavenDependencyPropertyUsageOverlap.java @@ -112,7 +112,7 @@ public static Set 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()) { diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/MavenCentralMirrorTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/MavenCentralMirrorTest.java index cf3f6305ef6..8d0a385fce9 100644 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/MavenCentralMirrorTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/MavenCentralMirrorTest.java @@ -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; @@ -71,6 +73,30 @@ class MavenCentralMirrorTest { """; + @Language("xml") + private static final String POM_WITH_PARENT = """ + + 4.0.0 + + org.example.hermetic + hermetic-parent + 1 + + my-app + + """; + + @Language("xml") + private static final String PARENT_POM = """ + + 4.0.0 + org.example.hermetic + hermetic-parent + 1 + pom + + """; + @Language("xml") private static final String METADATA = """ @@ -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), () -> { }); } @@ -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; @@ -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); @@ -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)); } }