You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by sl...@apache.org on 2021/06/01 20:36:11 UTC

[maven-dependency-plugin] branch MDEP-648 updated (2220ad9 -> 2f15be3)

This is an automated email from the ASF dual-hosted git repository.

slachiewicz pushed a change to branch MDEP-648
in repository https://gitbox.apache.org/repos/asf/maven-dependency-plugin.git.


 discard 2220ad9  MDEP-648: Add location of listed repository.
     add 9aa0fc0  [MDEP-714] Add analyze parameter "ignoreUnusedRuntime"
     add 36f8967  remove and .gitignore for dependency-reduced-pom.xml
     add a0cba78  rename doxiaSiteVersion property to doxiaSitetoolsVersion
     add 807f24d  [MDEP-749] document why excludeScope=test fails and what to do instead
     add 26abf6c  next version will be 3.2.0
     add 727c669  [MDEP-749] improve include/exclude scope documentation
     add 4211614  [MDEP-749] scope "threshold" term to summarise classpath in/ex-clusion
     add 9e28e06  Bump maven-shared-utils from 3.3.3 to 3.3.4
     add 0190eee  Merge pull request #132 from apache/dependabot/maven/org.apache.maven.shared-maven-shared-utils-3.3.4
     add 205c1a7  Disable merge commit button
     add b0942a6  [MDEP-739] Dependency Plugin go-offline doesn't respect artifact classifier
     add 0c7a2a8  (doc) Dependabot disable Java 8 deps
     new 2f15be3  MDEP-648: Add location of listed repository.

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (2220ad9)
            \
             N -- N -- N   refs/heads/MDEP-648 (2f15be3)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .asf.yaml                                          |   4 +
 .github/dependabot.yml                             |   7 +-
 .gitignore                                         |   1 +
 dependency-reduced-pom.xml                         | 426 ---------------------
 pom.xml                                            |   8 +-
 .../invoker.properties                             |   0
 .../pom.xml                                        |   7 +-
 .../src/main/java/Main.java                        |   0
 .../invoker.properties                             |   0
 .../pom.xml                                        |  13 +-
 .../verify.groovy                                  |  52 +--
 .../dependency/analyze/AbstractAnalyzeMojo.java    |  23 ++
 .../AbstractDependencyFilterMojo.java              |  34 +-
 .../dependency/resolvers/GoOfflineMojo.java        |   2 +
 14 files changed, 101 insertions(+), 476 deletions(-)
 delete mode 100644 dependency-reduced-pom.xml
 copy src/it/projects/{analyze => mdep-714-analyze-ignore-unused-runtime}/invoker.properties (100%)
 copy src/it/projects/{analyze-ignore-unused-declared-dependency => mdep-714-analyze-ignore-unused-runtime}/pom.xml (87%)
 copy src/it/projects/{analyze-ignore-unused-declared-dependency => mdep-714-analyze-ignore-unused-runtime}/src/main/java/Main.java (100%)
 copy src/it/projects/{go-offline => mdep-739-go-offline-respect-classifiers}/invoker.properties (100%)
 copy src/it/projects/{mdep-571-resolve-java9 => mdep-739-go-offline-respect-classifiers}/pom.xml (73%)
 copy src/it/projects/{mdep-450-project-without-ancestor => mdep-739-go-offline-respect-classifiers}/verify.groovy (88%)

[maven-dependency-plugin] 01/01: MDEP-648: Add location of listed repository.

Posted by sl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

slachiewicz pushed a commit to branch MDEP-648
in repository https://gitbox.apache.org/repos/asf/maven-dependency-plugin.git

commit 2f15be38d1e72af9e7ad1222df01eb28695e0da0
Author: Pim Moerenhout <pi...@gmail.com>
AuthorDate: Tue May 5 23:49:04 2020 +0200

    MDEP-648: Add location of listed repository.
---
 pom.xml                                            |   9 +
 .../invoker.properties                             |  37 +--
 src/it/projects/list-repositories-verbose/pom.xml  |  47 +++
 .../list-repositories-verbose/verify.groovy        |  26 ++
 .../projects/list-repositories/invoker.properties  |   1 +
 src/it/projects/list-repositories/verify.groovy    |  26 ++
 .../dependency/resolvers/ListRepositoriesMojo.java | 327 ++++++++++++++++++++-
 src/site/apt/usage.apt.vm                          |  11 +
 8 files changed, 457 insertions(+), 27 deletions(-)

diff --git a/pom.xml b/pom.xml
index b48a903..46db606 100644
--- a/pom.xml
+++ b/pom.xml
@@ -86,6 +86,9 @@ under the License.
     <contributor>
       <name>Maarten Mulders</name>
     </contributor>
+    <contributor>
+      <name>Pim Moerenhout</name>
+    </contributor>
   </contributors>
 
   <properties>
@@ -340,6 +343,12 @@ under the License.
         </exclusion>
       </exclusions>
     </dependency>
+    <dependency>
+      <groupId>org.apache.maven.wagon</groupId>
+      <artifactId>wagon-http-lightweight</artifactId>
+      <version>3.4.0</version>
+      <scope>provided</scope>
+    </dependency>
 
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
diff --git a/src/it/projects/list-repositories/invoker.properties b/src/it/projects/list-repositories-verbose/invoker.properties
similarity index 97%
copy from src/it/projects/list-repositories/invoker.properties
copy to src/it/projects/list-repositories-verbose/invoker.properties
index 6973bb1..48fda22 100644
--- a/src/it/projects/list-repositories/invoker.properties
+++ b/src/it/projects/list-repositories-verbose/invoker.properties
@@ -1,18 +1,19 @@
-# 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.
-
-invoker.goals = ${project.groupId}:${project.artifactId}:${project.version}:list-repositories
+# 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.
+
+invoker.goals = ${project.groupId}:${project.artifactId}:${project.version}:list-repositories
+invoker.debug = true
\ No newline at end of file
diff --git a/src/it/projects/list-repositories-verbose/pom.xml b/src/it/projects/list-repositories-verbose/pom.xml
new file mode 100644
index 0000000..9082485
--- /dev/null
+++ b/src/it/projects/list-repositories-verbose/pom.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.maven.its.dependency</groupId>
+  <artifactId>test</artifactId>
+  <version>1.0-SNAPSHOT</version>
+
+  <name>Test</name>
+  <description>
+    Test dependency:list-repositories
+  </description>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-project</artifactId>
+      <version>2.0.6</version>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/src/it/projects/list-repositories-verbose/verify.groovy b/src/it/projects/list-repositories-verbose/verify.groovy
new file mode 100644
index 0000000..68bdb6a
--- /dev/null
+++ b/src/it/projects/list-repositories-verbose/verify.groovy
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+File file = new File( basedir, "build.log" );
+assert file.exists();
+
+String buildLog = file.getText( "UTF-8" );
+assert buildLog.contains( 'location: Maven settings (user/global)' );
+
+return true;
diff --git a/src/it/projects/list-repositories/invoker.properties b/src/it/projects/list-repositories/invoker.properties
index 6973bb1..e79fcff 100644
--- a/src/it/projects/list-repositories/invoker.properties
+++ b/src/it/projects/list-repositories/invoker.properties
@@ -16,3 +16,4 @@
 # under the License.
 
 invoker.goals = ${project.groupId}:${project.artifactId}:${project.version}:list-repositories
+invoker.debug = false
\ No newline at end of file
diff --git a/src/it/projects/list-repositories/verify.groovy b/src/it/projects/list-repositories/verify.groovy
new file mode 100644
index 0000000..cb10938
--- /dev/null
+++ b/src/it/projects/list-repositories/verify.groovy
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+File file = new File( basedir, "build.log" );
+assert file.exists();
+
+String buildLog = file.getText( "UTF-8" );
+assert !buildLog.contains( 'location:' );
+
+return true;
diff --git a/src/main/java/org/apache/maven/plugins/dependency/resolvers/ListRepositoriesMojo.java b/src/main/java/org/apache/maven/plugins/dependency/resolvers/ListRepositoriesMojo.java
index deed8d3..f2fb18f 100644
--- a/src/main/java/org/apache/maven/plugins/dependency/resolvers/ListRepositoriesMojo.java
+++ b/src/main/java/org/apache/maven/plugins/dependency/resolvers/ListRepositoriesMojo.java
@@ -19,15 +19,36 @@ package org.apache.maven.plugins.dependency.resolvers;
  * under the License.
  */
 
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.ArtifactUtils;
 import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Repository;
+import org.apache.maven.model.building.ModelBuildingRequest;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugins.annotations.Component;
 import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.plugins.annotations.ResolutionScope;
 import org.apache.maven.plugins.dependency.AbstractDependencyMojo;
-import org.apache.maven.shared.transfer.dependencies.collect.CollectorResult;
-import org.apache.maven.shared.transfer.dependencies.collect.DependencyCollector;
-import org.apache.maven.shared.transfer.dependencies.collect.DependencyCollectorException;
+import org.apache.maven.project.DefaultProjectBuildingRequest;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.ProjectBuilder;
+import org.apache.maven.project.ProjectBuildingRequest;
+import org.apache.maven.settings.Mirror;
+import org.apache.maven.settings.Settings;
+import org.apache.maven.shared.transfer.artifact.ArtifactCoordinate;
+import org.apache.maven.shared.transfer.artifact.DefaultArtifactCoordinate;
+import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResolver;
+import org.apache.maven.shared.transfer.collection.CollectResult;
+import org.apache.maven.shared.transfer.collection.DependencyCollectionException;
+import org.apache.maven.shared.transfer.collection.DependencyCollector;
+import org.apache.maven.shared.transfer.graph.DependencyNode;
+import org.apache.maven.shared.transfer.graph.DependencyVisitor;
 
 /**
  * Goal that resolves all project dependencies and then lists the repositories used by the build and by the transitive
@@ -41,12 +62,46 @@ public class ListRepositoriesMojo
     extends AbstractDependencyMojo
 {
     /**
+     * Maven Project Builder component.
+     */
+    @Component
+    private ProjectBuilder projectBuilder;
+
+    /**
      * Dependency collector, needed to resolve dependencies.
      */
     @Component( role = DependencyCollector.class )
     private DependencyCollector dependencyCollector;
 
     /**
+     * Component used to resolve artifacts and download their files from remote repositories.
+     */
+    @Component
+    private ArtifactResolver artifactResolver;
+
+    /**
+     * The system settings for Maven. This is the instance resulting from
+     * merging global and user-level settings files.
+     */
+    @Parameter( defaultValue = "${settings}", readonly = true, required = true )
+    private Settings settings;
+
+    /**
+     * Remote repositories used for the project.
+     */
+    @Parameter( defaultValue = "${project.remoteArtifactRepositories}", required = true, readonly = true )
+    private List<ArtifactRepository> remoteRepositories;
+
+    /**
+     * Sets whether the plugin runs in verbose mode. As of plugin version 2.3, the default value is derived from Maven's
+     * global debug flag (compare command line switch <code>-X</code>). <br/>
+     *
+     * @since 3.1.2
+     */
+    @Parameter( property = "verbose" )
+    private boolean verbose;
+
+    /**
      * Displays a list of the repositories used by this build.
      *
      * @throws MojoExecutionException with a message if an error occurs.
@@ -55,22 +110,276 @@ public class ListRepositoriesMojo
     protected void doExecute()
         throws MojoExecutionException
     {
+
+        for ( ArtifactRepository artifactRepository : remoteRepositories )
+        {
+            verbose( "Maven remote repositories: " + repositoryAsString( artifactRepository ) );
+        }
+
+        final Set<ArtifactRepository> repositories = new HashSet<>();
+        final Set<Artifact> artifacts = new HashSet<>();
+
+        DependencyVisitor visitor = new DependencyVisitor()
+        {
+            @Override
+            public boolean visitEnter( DependencyNode dependencyNode )
+            {
+                repositories.addAll( dependencyNode.getRemoteRepositories() );
+                artifacts.add( dependencyNode.getArtifact() );
+                return true;
+            }
+
+            @Override
+            public boolean visitLeave( DependencyNode dependencyNode )
+            {
+                return true;
+            }
+        };
+
         try
         {
-            CollectorResult collectResult =
-                dependencyCollector.collectDependencies( session.getProjectBuildingRequest(), getProject().getModel() );
+            ProjectBuildingRequest projectBuildingRequest = session.getProjectBuildingRequest();
+
+            CollectResult collectResult =
+                dependencyCollector.collectDependencies( projectBuildingRequest, getProject().getModel() );
+
+            for ( Exception e : collectResult.getExceptions() )
+            {
+                throw new MojoExecutionException( "Collect dependencies failed", e );
+            }
+
+            collectResult.getRoot().accept( visitor );
+
+            verbose( "Artifacts used by the build of " + collectResult.getRoot().getArtifact() + ":" );
+            for ( Artifact artifact : artifacts )
+            {
+                verbose( " " + artifact.toString() );
+            }
 
             this.getLog().info( "Repositories used by this build:" );
+            for ( ArtifactRepository repo : repositories )
+            {
+                if ( isVerbose() )
+                {
+                    Set<String> locations = new HashSet<String>();
+                    for ( Mirror mirror : settings.getMirrors() )
+                    {
+                        if ( mirror.getId().equals( repo.getId() )
+                            && ( mirror.getUrl().equals( repo.getUrl() ) ) )
+                        {
+                            locations.add( "Maven settings (user/global)" );
+                        }
+                    }
+
+                    Artifact projectArtifact = getProject().getArtifact();
+                    MavenProject project = getMavenProject( ArtifactUtils.key( projectArtifact ) );
+                    traversePom( repo, projectArtifact, project, locations );
+
+                    for ( Artifact artifact : artifacts )
+                    {
+                        MavenProject artifactProject = getMavenProject( ArtifactUtils.key( artifact ) );
+                        traversePom( repo, artifact, artifactProject, locations );
+                    }
+                    writeRepository( repo, locations );
+                }
+                else
+                {
+                    this.getLog().info( repo.toString() );
+                }
+            }
+        }
+        catch ( DependencyCollectionException e )
+        {
+            throw new MojoExecutionException( "Unable to collect", e );
+        }
+    }
+
+    private void writeRepository( ArtifactRepository artifactRepository, Set<String> locations )
+    {
+        StringBuilder sb = new StringBuilder( 256 );
+        sb.append( artifactRepository.toString() );
+        for ( String location : locations )
+        {
+            sb.append( " location: " ).append( location ).append( System.lineSeparator() );
+        }
+        this.getLog().info( sb.toString() );
+    }
+
+    /**
+     * Parses the given String into GAV artifact coordinate information, adding the given type.
+     *
+     * @param artifactString should respect the format <code>groupId:artifactId[:version]</code>
+     * @param type The extension for the artifact, must not be <code>null</code>.
+     * @return the <code>Artifact</code> object for the <code>artifactString</code> parameter.
+     * @throws MojoExecutionException if the <code>artifactString</code> doesn't respect the format.
+     */
+    private ArtifactCoordinate getArtifactCoordinate( String artifactString, String type )
+        throws MojoExecutionException
+    {
+        if ( org.codehaus.plexus.util.StringUtils.isEmpty( artifactString ) )
+        {
+            throw new IllegalArgumentException( "artifact parameter could not be empty" );
+        }
+
+        String groupId; // required
+        String artifactId; // required
+        String version; // optional
+
+        String[] artifactParts = artifactString.split( ":" );
+        switch ( artifactParts.length )
+        {
+            case 2:
+                groupId = artifactParts[0];
+                artifactId = artifactParts[1];
+                version = Artifact.LATEST_VERSION;
+                break;
+            case 3:
+                groupId = artifactParts[0];
+                artifactId = artifactParts[1];
+                version = artifactParts[2];
+                break;
+            default:
+                throw new MojoExecutionException( "The artifact parameter '" + artifactString
+                    + "' should be conform to: " + "'groupId:artifactId[:version]'." );
+        }
+        return getArtifactCoordinate( groupId, artifactId, version, type );
+    }
+
+    private ArtifactCoordinate getArtifactCoordinate( String groupId, String artifactId, String version, String type )
+    {
+        DefaultArtifactCoordinate coordinate = new DefaultArtifactCoordinate();
+        coordinate.setGroupId( groupId );
+        coordinate.setArtifactId( artifactId );
+        coordinate.setVersion( version );
+        coordinate.setExtension( type );
+        return coordinate;
+    }
+
+    /**
+     * Retrieves the Maven Project associated with the given artifact String, in the form of
+     * <code>groupId:artifactId[:version]</code>. This resolves the POM artifact at those coordinates and then builds
+     * the Maven project from it.
+     *
+     * @param artifactString Coordinates of the Maven project to get.
+     * @return New Maven project.
+     * @throws MojoExecutionException If there was an error while getting the Maven project.
+     */
+    private MavenProject getMavenProject( String artifactString )
+        throws MojoExecutionException
+    {
+        ArtifactCoordinate coordinate = getArtifactCoordinate( artifactString, "pom" );
+        try
+        {
+            ProjectBuildingRequest pbr = new DefaultProjectBuildingRequest( session.getProjectBuildingRequest() );
+            pbr.setRemoteRepositories( remoteRepositories );
+            pbr.setProject( null );
+            pbr.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
+            pbr.setResolveDependencies( false );
+            Artifact artifact = artifactResolver.resolveArtifact( pbr, coordinate ).getArtifact();
+            return projectBuilder.build( artifact.getFile(), pbr ).getProject();
+        }
+        catch ( Exception e )
+        {
+            throw new MojoExecutionException( "Unable to get the POM for the artifact '" + artifactString
+                + "'. Verify the artifact parameter.", e );
+        }
+    }
+
+    private void traversePom( ArtifactRepository artifactRepository,
+                              Artifact artifact, MavenProject mavenProject, Set<String> locations )
+        throws MojoExecutionException
+    {
+        getLog().debug( "Looking for locations of repository " + repositoryAsString( artifactRepository )
+            + " for " + artifact );
+        if ( mavenProject != null )
+        {
+            for ( Repository repository : mavenProject.getOriginalModel().getRepositories() )
+            {
+                getLog().debug( "Found repository: " + repositoryAsString( repository )
+                    + " @ " + artifact + ":" + mavenProject.getOriginalModel().getPomFile() );
+                if ( isRepositoryEqual( repository, artifactRepository ) )
+                {
+                    locations.add( mavenProject.getModel().getPomFile().toString() );
+                }
+            }
+
+            traverseParentPom( artifactRepository, mavenProject, locations );
+        }
+        else
+        {
+            throw new MojoExecutionException( "No POM for the artifact '" + artifact + "'" );
+        }
+        return;
+    }
 
-            for ( ArtifactRepository repo : collectResult.getRemoteRepositories() )
+    private void traverseParentPom( ArtifactRepository artifactRepository,
+                                    MavenProject mavenProject, Set<String> locations )
+        throws MojoExecutionException
+    {
+        MavenProject parent = mavenProject.getParent();
+        if ( parent != null )
+        {
+            Model originalModel = parent.getOriginalModel();
+            if ( originalModel.getRepositories().size() != 0
+                || originalModel.getPluginRepositories().size() != 0 )
             {
-                this.getLog().info( repo.toString() );
+                String artifactKey =
+                    ArtifactUtils.key( parent.getGroupId(), parent.getArtifactId(), parent.getVersion() );
+                MavenProject parentPom = getMavenProject( artifactKey );
+
+                for ( Repository repository : originalModel.getRepositories() )
+                {
+                    getLog().debug( "Found parent repository " + repositoryAsString( repository )
+                        + " @ " + parentPom.getArtifact() + ":" + parentPom.getFile() );
+                    if ( isRepositoryEqual( repository, artifactRepository ) )
+                    {
+                        locations.add( parentPom.getFile().toString() );
+                    }
+                }
             }
+            traverseParentPom( artifactRepository, parent, locations );
         }
-        catch ( DependencyCollectorException e )
+        return;
+    }
+
+    private String repositoryAsString( Repository repository )
+    {
+        StringBuilder sb = new StringBuilder( 32 );
+        sb.append( repository.getId() );
+        sb.append( " (" );
+        sb.append( repository.getUrl() );
+        sb.append( ")" );
+        return sb.toString();
+    }
+
+    private String repositoryAsString( ArtifactRepository repository )
+    {
+        StringBuilder sb = new StringBuilder( 32 );
+        sb.append( repository.getId() );
+        sb.append( " (" );
+        sb.append( repository.getUrl() );
+        sb.append( ")" );
+        return sb.toString();
+    }
+
+    private boolean isVerbose()
+    {
+        return ( verbose || getLog().isDebugEnabled() );
+    }
+
+    private void verbose( String message )
+    {
+        if ( isVerbose() )
         {
-            throw new MojoExecutionException( "Unable to resolve artifacts", e );
+            getLog().info( message );
         }
     }
 
+    private boolean isRepositoryEqual( Repository repository, ArtifactRepository artifactRepository )
+    {
+        // TODO: Use org.apache.maven.RepositoryUtils in Maven or check also snapshots, etc.
+        return repository.getId().equals( artifactRepository.getId() )
+            && repository.getUrl().equals( artifactRepository.getUrl() );
+    }
+
 }
diff --git a/src/site/apt/usage.apt.vm b/src/site/apt/usage.apt.vm
index a67381c..9f912dc 100644
--- a/src/site/apt/usage.apt.vm
+++ b/src/site/apt/usage.apt.vm
@@ -685,6 +685,17 @@ mvn dependency:build-classpath -Dmdep.outputFile=cp.txt
   This goal is used to list all the repositories that this build depends upon. It will show repositories defined in your settings, 
   poms and declared in transitive dependency poms.
 
+  This goal can be executed from the command line:
+
++-----+
+mvn dependency:list-repositories
++-----+
+
+  Optionally, in verbose or debug mode it will display the location of the listed repository:
+
++-----+
+mvn dependency:list-repositories -Dverbose
++-----+
 
 * <<<dependency:get>>>