Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 33 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,48 @@ This Maven plugin generates dependency graphs on single modules or in an aggrega
For more information take a look at the [Plugin Documentation](https://ferstl.github.io/depgraph-maven-plugin/plugin-info.html), the [Release Notes](https://github.com/ferstl/depgraph-maven-plugin/wiki/Release-Notes) and the [Wiki](https://github.com/ferstl/depgraph-maven-plugin/wiki).


## Plugin Coordinates

## Getting Started
The *depgraph-maven-plugin* is available on [Maven Central](http://central.maven.org/maven2/com/github/ferstl/depgraph-maven-plugin/). So no further repository configuration is required.

These are the plugin coordinates:
### Run in your Maven Project
To use the plugin within your project, just add it to the `<build>` section:

<build>
<plugins>
<plugin>
<groupId>com.github.ferstl</groupId>
<artifactId>depgraph-maven-plugin</artifactId>
<version>3.2.2</version>
<configuration>
...
</configuration>
</plugin>
</plugins>
</build>

The release notes can be found in the [Wiki](https://github.com/ferstl/depgraph-maven-plugin/wiki/Release-Notes)

### Run on the Command Line
For ad-hoc dependency analysis the plugin can be used directly on the command line. To conveniently use this plugin on the command line it is recommended to add the groupId `com.github.ferstl` as "plugin group" in your Maven `settings.xml`:

<settings>
...
<pluginGroups>
<pluginGroup>com.github.ferstl</pluginGroup>
</pluginGroups>
...
</settings>

With this configuration you can use the short form `depgraph:<goal>` on the command line, e.g.

mvn depgraph:graph

Without defining the plugin group you need to fully qualify the plugin on the command line, e.g.:

# Latest version
mvn com.github.ferstl:depgraph-maven-plugin:graph

# Specific version
mvn com.github.ferstl:depgraph-maven-plugin:3.2.2:graph

## Examples

Expand Down Expand Up @@ -94,6 +118,11 @@ The goals [`depgraph:aggregate`](https://ferstl.github.io/depgraph-maven-plugin/
The goal [`depgraph:aggregate-by-groupid`](https://ferstl.github.io/depgraph-maven-plugin/aggregate-by-groupid-mojo.html) does the same for the group IDs of all modules and their dependencies.


### Graphs from Arbitrary Artifacts
The goal [`depgraph:for-artifact`](https://ferstl.github.io/depgraph-maven-plugin/for-artifact-mojo.html) creates a dependency graph for an arbitrary artifact. This goal can be executed without a Maven project at any place:

![Arbitrary Artifact](src/doc/for-artifact.png)

### Styling

This maven plugin offers you a variety of styling options for graphs in the DOT format. These options are explained in detail on the [Styling Wiki page](https://github.com/ferstl/depgraph-maven-plugin/wiki/Styling). This is an example of the aggregated graph with some custom styles:
Expand Down
Binary file added src/doc/for-artifact.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 18 additions & 4 deletions src/main/java/com/github/ferstl/depgraph/AbstractGraphMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@ abstract class AbstractGraphMojo extends AbstractMojo {
private boolean showAllAttributesForJson;

/**
* Output directory to write the dependency graph to.
* Output directory to write the dependency graph to. The default is the project's build directory. For goals that
* don't require a project the current directory will be used.
*
* @since 2.2.0
*/
Expand Down Expand Up @@ -237,7 +238,7 @@ abstract class AbstractGraphMojo extends AbstractMojo {
private boolean printStyleConfiguration;

/**
* Skip execution when set to {@true}.
* Skip execution when set to {@code true}.
*
* @since 3.3.0
*/
Expand Down Expand Up @@ -273,7 +274,7 @@ public final void execute() throws MojoExecutionException, MojoFailureException

try {
GraphFactory graphFactory = createGraphFactory(globalFilter, transitiveIncludeExcludeFilter, targetFilter, graphStyleConfigurer);
String dependencyGraph = graphFactory.createGraph(this.project);
String dependencyGraph = graphFactory.createGraph(getProject());
writeGraphFile(dependencyGraph, graphFilePath);

if (graphFormat == GraphFormat.DOT && this.createImage) {
Expand Down Expand Up @@ -312,6 +313,10 @@ protected boolean showFullGraph() {
return GraphFormat.forName(this.graphFormat) == JSON && this.showAllAttributesForJson;
}

protected MavenProject getProject() {
return this.project;
}

private ArtifactFilter createGlobalArtifactFilter() {
AndArtifactFilter filter = new AndArtifactFilter();

Expand Down Expand Up @@ -422,7 +427,12 @@ private Path createGraphFilePath(GraphFormat graphFormat) {
String fileName = this.useArtifactIdInFileName ? this.artifactId : this.outputFileName;
fileName = addFileExtensionIfNeeded(graphFormat, fileName);

return this.outputDirectory.toPath().resolve(fileName);
// ${project.build.directory} is not resolved when run without a POM file (e.g. for the for-artifact goal)
if (isOutputDirectoryResolved()) {
return this.outputDirectory.toPath().resolve(fileName);
}

return Paths.get(System.getProperty("user.dir"), fileName);
}

private String addFileExtensionIfNeeded(GraphFormat graphFormat, String fileName) {
Expand All @@ -434,6 +444,10 @@ private String addFileExtensionIfNeeded(GraphFormat graphFormat, String fileName
return fileName;
}

private boolean isOutputDirectoryResolved() {
return !this.outputDirectory.toString().contains("${project.basedir}");
}

private void writeGraphFile(String graph, Path graphFilePath) throws IOException {
Path parent = graphFilePath.getParent();
if (parent != null) {
Expand Down
103 changes: 103 additions & 0 deletions src/main/java/com/github/ferstl/depgraph/ForArtifactMojo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package com.github.ferstl.depgraph;

import java.util.List;
import org.apache.maven.artifact.DefaultArtifact;
import org.apache.maven.artifact.handler.DefaultArtifactHandler;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
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.project.DefaultProjectBuildingRequest;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuilder;
import org.apache.maven.project.ProjectBuildingException;
import org.apache.maven.project.ProjectBuildingRequest;

/**
* Creates a dependency graph from an arbitrary artifact.
*
* @since 3.3.0
*/
@Mojo(
name = "for-artifact",
defaultPhase = LifecyclePhase.NONE,
requiresProject = false,
requiresDirectInvocation = true,
requiresDependencyCollection = ResolutionScope.NONE,
requiresDependencyResolution = ResolutionScope.NONE,
threadSafe = true)
public class ForArtifactMojo extends DependencyGraphMojo {

/**
* The {@code gropId} of the artifact.
*
* @since 3.3.0
*/
@Parameter(property = "groupId", required = true)
private String groupId;

/**
* The {@code artifactId} of the artifact.
*
* @since 3.3.0
*/
@Parameter(property = "artifactId", required = true)
private String artifactId;

/**
* The {@code version} of the artifact.
*
* @since 3.3.0
*/
@Parameter(property = "version", required = true)
private String version;

/**
* The {@code type} of the artifact.
*
* @since 3.3.0
*/
@Parameter(property = "type", defaultValue = "jar")
private String type;

/**
* The {@code classifier} of the artifact.
*
* @since 3.3.0
*/
@Parameter(property = "classifier", defaultValue = "")
private String classifier;

/**
* The {@code artifactId} of the artifact.
*
* @since 3.3.0
*/
@Parameter(property = "profiles")
private List<String> profiles;

@Parameter(defaultValue = "${session}", readonly = true, required = true)
private MavenSession session;

@Component
private ProjectBuilder projectBuilder;

@Override
public MavenProject getProject() {
ProjectBuildingRequest buildingRequest = new DefaultProjectBuildingRequest(this.session.getProjectBuildingRequest());
buildingRequest.setRepositorySession(this.session.getRepositorySession());
buildingRequest.setProject(null);
buildingRequest.setResolveDependencies(true);
buildingRequest.setActiveProfileIds(this.profiles);

DefaultArtifact artifact = new DefaultArtifact(this.groupId, this.artifactId, this.version, "compile", this.type, this.classifier, new DefaultArtifactHandler());
try {
return this.projectBuilder.build(artifact, buildingRequest).getProject();
} catch (ProjectBuildingException e) {
throw new IllegalStateException("Error while creating Maven project from Artifact '" + artifact + "'.", e);
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import io.takari.maven.testing.executor.MavenRuntime;
import io.takari.maven.testing.executor.MavenVersions;
import io.takari.maven.testing.executor.junit.MavenJUnitTestRunner;

import static io.takari.maven.testing.TestResources.assertFilesPresent;
import static java.nio.file.Files.copy;
import static java.nio.file.Files.createDirectories;
Expand Down Expand Up @@ -228,6 +227,22 @@ public void pumlWithConflicts() throws Exception {
collectFile("sub-parent/module-3/target/dependency-graph.puml", "with-conflicts.puml");
}

@Test
public void forArtifact() throws Exception {
runTest("for-artifact",
"-DgraphFormat=dot",
"-DexcludeOptionalDependencies",
"-DgroupId=org.springframework",
"-DartifactId=spring-jdbc",
"-Dversion=5.1.3.RELEASE");

assertFilesPresent(
this.basedir,
"target/dependency-graph.png");

collectFile("target/dependency-graph.png", "for-artifact.png");
}

private void runTest(String goal, String... cliOptions) throws Exception {
File basedir = getBaseDir();
MavenExecution execution = this.mavenRuntime.forProject(basedir);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package com.github.ferstl.depgraph;

import java.io.File;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import io.takari.maven.testing.TestProperties;
import io.takari.maven.testing.TestResources;
import io.takari.maven.testing.executor.MavenExecutionResult;
import io.takari.maven.testing.executor.MavenRuntime;
import io.takari.maven.testing.executor.MavenVersions;
import io.takari.maven.testing.executor.junit.MavenJUnitTestRunner;
import static io.takari.maven.testing.TestResources.assertFileContents;

@RunWith(MavenJUnitTestRunner.class)
@MavenVersions({"3.6.0", "3.1.0"})
public class ForArtifactIntegrationTest {

@Rule
public final TestResources resources = new TestResources();

private final MavenRuntime mavenRuntime;
private final TestProperties testProperties;

public ForArtifactIntegrationTest(MavenRuntime.MavenRuntimeBuilder builder) throws Exception {
this.testProperties = new TestProperties();
this.mavenRuntime = builder.build();
}

@Test
public void runWithoutProject() throws Exception {
// arrange
File basedir = this.resources.getBasedir("no-project");

// act
MavenExecutionResult result = this.mavenRuntime
.forProject(basedir)
.withCliOption("-B")
.withCliOption("-DgroupId=org.springframework")
.withCliOption("-DartifactId=spring-jdbc")
.withCliOption("-Dversion=5.1.3.RELEASE")
.withCliOption("-DshowVersions")
.withCliOption("-DgraphFormat=text")
.execute(createFullyQualifiedGoal());

// assert
result.assertErrorFreeLog();
assertFileContents(basedir, "expectations/spring-jdbc.txt", "dependency-graph.txt");
}

@Test
public void runWithProject() throws Exception {
// arrange
File basedir = this.resources.getBasedir("single-dependency");

// act
MavenExecutionResult result = this.mavenRuntime
.forProject(basedir)
.withCliOption("-B")
.withCliOption("-DgroupId=com.google.guava")
.withCliOption("-DartifactId=guava")
.withCliOption("-Dversion=27.0-jre")
.withCliOption("-DshowGroupIds")
.withCliOption("-DshowVersions")
.withCliOption("-DgraphFormat=text")
.execute(createFullyQualifiedGoal());

// assert
result.assertErrorFreeLog();
assertFileContents(basedir, "expectations/guava.txt", "target/dependency-graph.txt");
}

@Test
public void runWithInexistentArtifact() throws Exception {
// arrange
File basedir = this.resources.getBasedir("no-project");

// act
MavenExecutionResult result = this.mavenRuntime
.forProject(basedir)
.withCliOption("-B")
.withCliOption("-DgroupId=com.google.guava")
.withCliOption("-DartifactId=guava")
.withCliOption("-Dversion=000000abxdce")
.execute(createFullyQualifiedGoal());

// assert
result.assertLogText("[ERROR] Failed to execute goal com.github.ferstl:depgraph-maven-plugin");
result.assertLogText("com.google.guava:guava:jar:000000abxdce:compile");
}

/**
* Helper to create a fully qualified Maven goal with the curren plugin version. This is needed for tests
* without POM files where {@code it-plugin.version} can not be injected.
*
* @return The fully qualified goal {@code <groupId>:<artifactId>:<version>:for-artifact}
*/
private String createFullyQualifiedGoal() {
return this.testProperties.get("project.groupId") + ":"
+ this.testProperties.get("project.artifactId") + ":"
+ this.testProperties.get("project.version") + ":"
+ "for-artifact";
}
}
17 changes: 17 additions & 0 deletions src/test/projects/no-project/expectations/spring-jdbc.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
spring-jdbc:5.1.3.RELEASE:compile
+- spring-beans:5.1.3.RELEASE:compile
+- spring-core:5.1.3.RELEASE:compile
| \- spring-jcl:5.1.3.RELEASE:compile
+- spring-tx:5.1.3.RELEASE:compile
+- h2:1.4.197:compile (optional)
+- javax.transaction-api:1.3:compile (optional)
+- derby:10.14.2.0:compile (optional)
+- derbyclient:10.14.2.0:compile (optional)
+- hsqldb:2.4.1:compile (optional)
+- kotlin-reflect:1.2.71:compile (optional)
+- kotlin-stdlib:1.2.71:compile (optional)
| +- kotlin-stdlib-common:1.2.71:compile (optional)
| \- annotations:13.0:compile (optional)
\- spring-context:5.1.3.RELEASE:compile (optional)
+- spring-aop:5.1.3.RELEASE:compile (optional)
\- spring-expression:5.1.3.RELEASE:compile (optional)
Empty file.
9 changes: 9 additions & 0 deletions src/test/projects/single-dependency/expectations/guava.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
com.google.guava:guava:27.0-jre:compile
+- com.google.guava:failureaccess:1.0:compile
+- com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava:compile
+- com.google.code.findbugs:jsr305:3.0.2:compile
+- org.checkerframework:checker-qual:2.5.2:compile
+- com.google.errorprone:error_prone_annotations:2.2.0:compile
+- com.google.j2objc:j2objc-annotations:1.1:compile
+- org.codehaus.mojo:animal-sniffer-annotations:1.17:compile
\- jdk:srczip:999:system (optional)