diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/MavenExecutionContextView.java b/rewrite-maven/src/main/java/org/openrewrite/maven/MavenExecutionContextView.java index 73e29721cc..49ae55012a 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/MavenExecutionContextView.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/MavenExecutionContextView.java @@ -188,10 +188,27 @@ public List getRepositories() { */ public List getRepositories(@Nullable MavenSettings mavenSettings, @Nullable List activeProfiles) { + List contextRepos = getMessage(MAVEN_REPOSITORIES, emptyList()); if (mavenSettings != null) { - return mapRepositories(mavenSettings, activeProfiles == null ? emptyList() : activeProfiles); + List settingsRepos = mapRepositories(mavenSettings, activeProfiles == null ? emptyList() : activeProfiles); + if (contextRepos.isEmpty()) { + return settingsRepos; + } + // Include both settings-derived repos and context repos, settings repos take precedence by ID + Map result = new LinkedHashMap<>(); + for (MavenRepository repo : settingsRepos) { + if (repo.getId() != null) { + result.put(repo.getId(), repo); + } + } + for (MavenRepository repo : contextRepos) { + if (repo.getId() != null) { + result.putIfAbsent(repo.getId(), repo); + } + } + return new ArrayList<>(result.values()); } - return getMessage(MAVEN_REPOSITORIES, emptyList()); + return contextRepos; } /** diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/internal/MavenPomDownloaderTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/internal/MavenPomDownloaderTest.java index 5456eddd97..add7f3d618 100755 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/internal/MavenPomDownloaderTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/internal/MavenPomDownloaderTest.java @@ -149,6 +149,172 @@ void repositoryOrder() { ); } + @Issue("https://github.com/moderneinc/customer-requests/issues/2122") + @Test + void settingsReposUsedWhenPomRepoFails(@TempDir Path tempDir) throws Exception { + // Create a working settings repo with the artifact + Path settingsRepoDir = tempDir.resolve("settings-repo"); + Path artifactDir = settingsRepoDir.resolve("com/example/my-lib/1.0.0"); + Files.createDirectories(artifactDir); + Files.writeString(artifactDir.resolve("my-lib-1.0.0.pom"), + //language=xml + """ + + com.example + my-lib + 1.0.0 + + """); + Files.writeString(artifactDir.resolve("my-lib-1.0.0.jar"), "I'm a jar"); + + // Create a broken POM repo (empty, has no artifacts) + Path brokenRepoDir = tempDir.resolve("broken-repo"); + Files.createDirectories(brokenRepoDir); + + // Set up Maven settings with the working repo in a profile + var ctx = MavenExecutionContextView.view(new InMemoryExecutionContext()); + ctx.setMavenSettings(MavenSettings.parse(Parser.Input.fromString(Path.of("settings.xml"), + //language=xml + """ + + + + my-repos + + + settings-repo + %s + + + + + + my-repos + + + """.formatted(settingsRepoDir.toUri()) + ), ctx)); + + var gav = new GroupArtifactVersion("com.example", "my-lib", "1.0.0"); + + // The POM repo doesn't have the artifact, but settings repo does. + // The download should succeed by falling through to the settings repo. + var brokenRepo = MavenRepository.builder() + .id("broken-repo") + .uri(brokenRepoDir.toUri().toString()) + .knownToExist(true) + .build(); + + Pom pom = assertDoesNotThrow(() -> + new MavenPomDownloader(emptyMap(), ctx) + .download(gav, null, null, List.of(brokenRepo))); + assertThat(pom.getGroupId()).isEqualTo("com.example"); + assertThat(pom.getArtifactId()).isEqualTo("my-lib"); + } + + @Issue("https://github.com/moderneinc/customer-requests/issues/2122") + @Test + void contextReposUsedWhenPomRepoFails(@TempDir Path tempDir) throws Exception { + // Create a working repo with the artifact + Path workingRepoDir = tempDir.resolve("working-repo"); + Path artifactDir = workingRepoDir.resolve("com/example/my-lib/1.0.0"); + Files.createDirectories(artifactDir); + Files.writeString(artifactDir.resolve("my-lib-1.0.0.pom"), + //language=xml + """ + + com.example + my-lib + 1.0.0 + + """); + Files.writeString(artifactDir.resolve("my-lib-1.0.0.jar"), "I'm a jar"); + + // Create a broken POM repo (empty, has no artifacts) + Path brokenRepoDir = tempDir.resolve("broken-repo"); + Files.createDirectories(brokenRepoDir); + + // Set repos directly on context (without MavenSettings) + var ctx = MavenExecutionContextView.view(new InMemoryExecutionContext()); + var workingRepo = MavenRepository.builder() + .id("working-repo") + .uri(workingRepoDir.toUri().toString()) + .knownToExist(true) + .build(); + ctx.setRepositories(List.of(workingRepo)); + + var gav = new GroupArtifactVersion("com.example", "my-lib", "1.0.0"); + + var brokenRepo = MavenRepository.builder() + .id("broken-repo") + .uri(brokenRepoDir.toUri().toString()) + .knownToExist(true) + .build(); + + // Download should succeed using context repo when POM repo fails + Pom pom = assertDoesNotThrow(() -> + new MavenPomDownloader(emptyMap(), ctx) + .download(gav, null, null, List.of(brokenRepo))); + assertThat(pom.getGroupId()).isEqualTo("com.example"); + assertThat(pom.getArtifactId()).isEqualTo("my-lib"); + } + + @Issue("https://github.com/moderneinc/customer-requests/issues/2122") + @Test + void contextReposNotLostWhenMavenSettingsPresent(@TempDir Path tempDir) throws Exception { + // Create a working repo with the artifact + Path workingRepoDir = tempDir.resolve("working-repo"); + Path artifactDir = workingRepoDir.resolve("com/example/my-lib/1.0.0"); + Files.createDirectories(artifactDir); + Files.writeString(artifactDir.resolve("my-lib-1.0.0.pom"), + //language=xml + """ + + com.example + my-lib + 1.0.0 + + """); + Files.writeString(artifactDir.resolve("my-lib-1.0.0.jar"), "I'm a jar"); + + // Create a broken POM repo (empty, has no artifacts) + Path brokenRepoDir = tempDir.resolve("broken-repo"); + Files.createDirectories(brokenRepoDir); + + // Set up Maven settings with NO profiles/repos + var ctx = MavenExecutionContextView.view(new InMemoryExecutionContext()); + ctx.setMavenSettings(MavenSettings.parse(Parser.Input.fromString(Path.of("settings.xml"), + //language=xml + """ + + + """ + ), ctx)); + + // Add repos directly on the context AFTER setting maven settings + var workingRepo = MavenRepository.builder() + .id("working-repo") + .uri(workingRepoDir.toUri().toString()) + .knownToExist(true) + .build(); + ctx.setRepositories(List.of(workingRepo)); + + var gav = new GroupArtifactVersion("com.example", "my-lib", "1.0.0"); + + var brokenRepo = MavenRepository.builder() + .id("broken-repo") + .uri(brokenRepoDir.toUri().toString()) + .knownToExist(true) + .build(); + + // Download should succeed using the context repo even though MavenSettings is set + Pom pom = assertDoesNotThrow(() -> + new MavenPomDownloader(emptyMap(), ctx) + .download(gav, null, null, List.of(brokenRepo))); + assertThat(pom.getGroupId()).isEqualTo("com.example"); + assertThat(pom.getArtifactId()).isEqualTo("my-lib"); + } + @Nested class WithNativeHttpURLConnectionAndTLS { private final ExecutionContext ctx = HttpSenderExecutionContextView.view(new InMemoryExecutionContext())