diff --git a/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index b6ac66cbb395..51ee3e0d0137 100644 --- a/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -439,6 +439,17 @@ ProjectBuildingResult build(boolean parent, Path pomFile, ModelSource modelSourc } } + private boolean isProjectPom(Path pomFile) { + List projects = session.getProjects(); + if (pomFile == null || projects == null) { // no reactor yet while the session is being set up + return false; + } + Path path = pomFile.toAbsolutePath().normalize(); + return projects.stream() + .filter(Objects::nonNull) + .anyMatch(p -> p.getPomPath().toAbsolutePath().normalize().equals(path)); + } + ProjectBuildingResult build( boolean parent, Artifact artifact, boolean allowStubModel, List repositories) throws ProjectBuildingException { @@ -463,7 +474,10 @@ ProjectBuildingResult build( ArtifactResolverResult.ResultItem resItem = res.getResult(coordinates); pomArtifact = InternalMavenSession.from(session).toArtifact(resItem.getArtifact()); - localProject = resItem.getRepository() instanceof org.apache.maven.api.WorkspaceRepository; + // the workspace also serves copies from the project-local repository; only a POM that belongs to + // a project of this session is a checkout with a basedir, the rest is treated like a repository + localProject = resItem.getRepository() instanceof org.apache.maven.api.WorkspaceRepository + && isProjectPom(pomArtifact.getPath()); } catch (ArtifactResolverException e) { if (e.getResult().getResults().values().iterator().next().isMissing() && allowStubModel) { return build(parent, null, createStubModelSource(artifact)); diff --git a/impl/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java b/impl/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java index fd35d876018e..bc796ec8696d 100644 --- a/impl/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java +++ b/impl/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java @@ -57,6 +57,7 @@ import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.WorkspaceReader; import static org.codehaus.plexus.testing.PlexusExtension.getBasedir; @@ -172,6 +173,7 @@ protected void initRepoSession( RepositorySystemSession session = new MavenSessionBuilderSupplier(repositorySystem, true) .get() .withLocalRepositories(localRepo) + .setWorkspaceReader(getWorkspaceReader()) .build(); projectBuildingRequest.setRepositorySession(session); @@ -194,6 +196,13 @@ protected void initRepoSession( sessionScope.seed(InternalMavenSession.class, InternalMavenSession.from(iSession)); } + /** + * The workspace reader of the repository session, none by default. + */ + protected WorkspaceReader getWorkspaceReader() { + return null; + } + protected MavenProject createStubMavenProject() { Model model = new Model(); model.setGroupId("org.apache.maven.test"); diff --git a/impl/maven-core/src/test/java/org/apache/maven/project/WorkspaceParentProjectBuilderTest.java b/impl/maven-core/src/test/java/org/apache/maven/project/WorkspaceParentProjectBuilderTest.java new file mode 100644 index 000000000000..ad4b0e259de1 --- /dev/null +++ b/impl/maven-core/src/test/java/org/apache/maven/project/WorkspaceParentProjectBuilderTest.java @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.maven.project; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import org.apache.maven.AbstractCoreMavenComponentTestCase; +import org.apache.maven.execution.MavenSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.repository.WorkspaceReader; +import org.eclipse.aether.repository.WorkspaceRepository; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +/** + * A parent served by the workspace reader gets a basedir only when it is a project of the session. + * The reactor reader also serves what it stored in the project-local repository, and such a parent + * must look like one resolved from a repository, as on Maven 3. + */ +class WorkspaceParentProjectBuilderTest extends AbstractCoreMavenComponentTestCase { + + private static final String GROUP_ID = "org.apache.maven.its.workspace"; + + @TempDir + Path tempDir; + + private Path workspaceParentPom; + + @Override + protected String getProjectsDirectory() { + return "src/test/projects/project-builder"; + } + + @Override + protected WorkspaceReader getWorkspaceReader() { + return new WorkspaceReader() { + private final WorkspaceRepository repository = new WorkspaceRepository("test"); + + @Override + public WorkspaceRepository getRepository() { + return repository; + } + + @Override + public File findArtifact(Artifact artifact) { + boolean parentPom = GROUP_ID.equals(artifact.getGroupId()) + && "parent".equals(artifact.getArtifactId()) + && "pom".equals(artifact.getExtension()); + return parentPom && workspaceParentPom != null ? workspaceParentPom.toFile() : null; + } + + @Override + public List findVersions(Artifact artifact) { + return findArtifact(artifact) != null ? List.of(artifact.getVersion()) : List.of(); + } + }; + } + + @Test + void parentFromProjectLocalRepositoryHasNoBasedir() throws Exception { + workspaceParentPom = writePom(tempDir.resolve(".mvn/target/project-local-repo/parent-1.pom"), "parent"); + MavenSession session = createMavenSession( + writePom(tempDir.resolve("other/pom.xml"), "other").toFile()); + + MavenProject parent = buildChild(session).getParent(); + + assertNotNull(parent); + assertNull(parent.getFile()); + assertNull(parent.getBasedir()); + } + + @Test + void parentOfTheSessionKeepsItsBasedir() throws Exception { + workspaceParentPom = writePom(tempDir.resolve("parent/pom.xml"), "parent"); + MavenSession session = createMavenSession(workspaceParentPom.toFile()); + + MavenProject parent = buildChild(session).getParent(); + + assertNotNull(parent); + assertEquals(workspaceParentPom.toFile(), parent.getFile()); + assertEquals(workspaceParentPom.getParent().toFile(), parent.getBasedir()); + } + + private MavenProject buildChild(MavenSession session) throws Exception { + Path childPom = tempDir.resolve("child/pom.xml"); + Files.createDirectories(childPom.getParent()); + Files.writeString(childPom, """ + + 4.0.0 + + %s + parent + 1 + + + child + + """.formatted(GROUP_ID)); + ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest(); + configuration.setRepositorySession(session.getRepositorySession()); + return projectBuilder.build(childPom.toFile(), configuration).getProject(); + } + + private static Path writePom(Path pom, String artifactId) throws IOException { + Files.createDirectories(pom.getParent()); + Files.writeString(pom, """ + + 4.0.0 + %s + %s + 1 + pom + + """.formatted(GROUP_ID, artifactId)); + return pom; + } +}