diff --git a/rewrite-python/src/integTest/java/org/openrewrite/python/ParseProjectIntegTest.java b/rewrite-python/src/integTest/java/org/openrewrite/python/ParseProjectIntegTest.java index 19a019d4aac..241ae83902c 100644 --- a/rewrite-python/src/integTest/java/org/openrewrite/python/ParseProjectIntegTest.java +++ b/rewrite-python/src/integTest/java/org/openrewrite/python/ParseProjectIntegTest.java @@ -254,6 +254,50 @@ void pyprojectTomlTakesPriorityOverRequirementsTxt() throws IOException { } + @Test + @Timeout(value = 60, unit = TimeUnit.SECONDS) + void includesAllRequirementsTxtFiles() throws IOException { + Path projectDir = tempDir.resolve("multi_requirements"); + Files.createDirectories(projectDir); + + Files.writeString(projectDir.resolve("main.py"), "x = 1"); + Files.writeString(projectDir.resolve("requirements.txt"), """ + requests>=2.28.0 + """); + Files.writeString(projectDir.resolve("requirements-dev.txt"), """ + pytest>=7.0 + """); + + List sources = client() + .parseProject(projectDir, new InMemoryExecutionContext()) + .collect(Collectors.toList()); + + assertThat(sources) + .extracting(sf -> sf.getSourcePath().getFileName().toString()) + .contains("main.py", "requirements.txt", "requirements-dev.txt"); + + SourceFile reqsTxt = sources.stream() + .filter(s -> s.getSourcePath().getFileName().toString().equals("requirements.txt")) + .findFirst() + .orElseThrow(() -> new AssertionError("Missing requirements.txt")); + SourceFile reqsDevTxt = sources.stream() + .filter(s -> s.getSourcePath().getFileName().toString().equals("requirements-dev.txt")) + .findFirst() + .orElseThrow(() -> new AssertionError("Missing requirements-dev.txt")); + + assertThat(reqsTxt).isInstanceOf(PlainText.class); + assertThat(reqsDevTxt).isInstanceOf(PlainText.class); + + PythonResolutionResult baseMarker = reqsTxt.getMarkers().findFirst(PythonResolutionResult.class).orElse(null); + PythonResolutionResult devMarker = reqsDevTxt.getMarkers().findFirst(PythonResolutionResult.class).orElse(null); + assertThat(baseMarker).as("PythonResolutionResult marker on requirements.txt").isNotNull(); + assertThat(devMarker).as("PythonResolutionResult marker on requirements-dev.txt").isNotNull(); + + // Each file should have its own distinct marker pointing to its own path + assertThat(baseMarker.getPath()).isEqualTo("requirements.txt"); + assertThat(devMarker.getPath()).isEqualTo("requirements-dev.txt"); + } + private PythonRewriteRpc client() { return PythonRewriteRpc.getOrStart(); } diff --git a/rewrite-python/src/main/java/org/openrewrite/python/rpc/PythonRewriteRpc.java b/rewrite-python/src/main/java/org/openrewrite/python/rpc/PythonRewriteRpc.java index 13a40385e36..f61f70dfba6 100644 --- a/rewrite-python/src/main/java/org/openrewrite/python/rpc/PythonRewriteRpc.java +++ b/rewrite-python/src/main/java/org/openrewrite/python/rpc/PythonRewriteRpc.java @@ -340,14 +340,13 @@ private Stream parseManifest(Path projectPath, @Nullable Path relati RequirementsTxtParser reqsParser = new RequirementsTxtParser(commandEnv); try (Stream entries = Files.list(projectPath)) { - Path reqsPath = entries - .filter(p -> reqsParser.accept(p.getFileName())) - .findFirst() - .orElse(null); - if (reqsPath != null) { - Parser.Input input = Parser.Input.fromFile(reqsPath); - return reqsParser.parseInputs( - Collections.singletonList(input), effectiveRelativeTo, ctx); + List reqInputs = new ArrayList<>(); + entries.filter(p -> reqsParser.accept(p.getFileName())) + .sorted() + .map(Parser.Input::fromFile) + .forEach(reqInputs::add); + if (!reqInputs.isEmpty()) { + return reqsParser.parseInputs(reqInputs, effectiveRelativeTo, ctx); } } catch (IOException e) { // Silently skip manifest parsing if we can't list the directory