Skip to content

Commit e557b7e

Browse files
committed
Merge pull request #7 from davidburkhart/master
Cleanup & add target/test-classes to package cycle check
2 parents 32d5de1 + 696dcaf commit e557b7e

File tree

1,724 files changed

+22274
-22227
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,724 files changed

+22274
-22227
lines changed

README.md

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,38 @@
1-
[![Build Status](https://buildhive.cloudbees.com/job/andrena/job/no-package-cycles-enforcer-rule/badge/icon)](https://buildhive.cloudbees.com/job/andrena/job/no-package-cycles-enforcer-rule/)
2-
3-
This Maven Enforcer Rule checks your project for package cycles. It fails the build if any package cycle is found, showing you the packages and classes involved in the cycle.
4-
5-
Usage: Add the following plugin to your POM:
6-
7-
```
8-
<plugin>
9-
<artifactId>maven-enforcer-plugin</artifactId>
10-
<version>1.2</version>
11-
<dependencies>
12-
<dependency>
13-
<groupId>de.andrena.tools.nopackagecycles</groupId>
14-
<artifactId>no-package-cycles-enforcer-rule</artifactId>
15-
<version>1.0.4</version>
16-
</dependency>
17-
</dependencies>
18-
<executions>
19-
<execution>
20-
<id>enforce-no-package-cycles</id>
21-
<goals>
22-
<goal>enforce</goal>
23-
</goals>
24-
<phase>compile</phase>
25-
<configuration>
26-
<rules>
27-
<NoPackageCyclesRule implementation="de.andrena.tools.nopackagecycles.NoPackageCyclesRule" />
28-
</rules>
29-
</configuration>
30-
</execution>
31-
</executions>
32-
</plugin>
33-
```
34-
35-
See also:
36-
* The original version by Daniel Seidewitz on [Stackoverflow](http://stackoverflow.com/questions/3416547/maven-jdepend-fail-build-with-cycles). Improved by showing all packages afflicted with cycles and the corresponding classes importing the conflicting packages.
37-
* [JDepend](https://github.com/clarkware/jdepend), the library being used to detect package cycles.
38-
* For more information about package cycles, see ["The Acyclic Dependencies Principle" by Robert C. Martin (Page 6)](http://www.objectmentor.com/resources/articles/granularity.pdf).
1+
[![Build Status](https://buildhive.cloudbees.com/job/andrena/job/no-package-cycles-enforcer-rule/badge/icon)](https://buildhive.cloudbees.com/job/andrena/job/no-package-cycles-enforcer-rule/)
2+
3+
This Maven Enforcer Rule checks your project for package cycles. It fails the build if any package cycle is found, showing you the packages and classes involved in the cycle.
4+
5+
Usage: Add the following plugin to your POM:
6+
7+
```
8+
<plugin>
9+
<artifactId>maven-enforcer-plugin</artifactId>
10+
<version>1.2</version>
11+
<dependencies>
12+
<dependency>
13+
<groupId>de.andrena.tools.nopackagecycles</groupId>
14+
<artifactId>no-package-cycles-enforcer-rule</artifactId>
15+
<version>1.0.4</version>
16+
</dependency>
17+
</dependencies>
18+
<executions>
19+
<execution>
20+
<id>enforce-no-package-cycles</id>
21+
<goals>
22+
<goal>enforce</goal>
23+
</goals>
24+
<phase>test-compile</phase>
25+
<configuration>
26+
<rules>
27+
<NoPackageCyclesRule implementation="de.andrena.tools.nopackagecycles.NoPackageCyclesRule" />
28+
</rules>
29+
</configuration>
30+
</execution>
31+
</executions>
32+
</plugin>
33+
```
34+
35+
See also:
36+
* The original version by Daniel Seidewitz on [Stackoverflow](http://stackoverflow.com/questions/3416547/maven-jdepend-fail-build-with-cycles). Improved by showing all packages afflicted with cycles and the corresponding classes importing the conflicting packages.
37+
* [JDepend](https://github.com/clarkware/jdepend), the library being used to detect package cycles.
38+
* For more information about package cycles, see ["The Acyclic Dependencies Principle" by Robert C. Martin (Page 6)](http://www.objectmentor.com/resources/articles/granularity.pdf).

pom.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@
109109
<includes>
110110
<include>**/*IntegrationTest.java</include>
111111
</includes>
112+
<encoding>UTF-8</encoding>
112113
</configuration>
113114
</plugin>
114115
<plugin>
@@ -118,7 +119,7 @@
118119
<dependency>
119120
<groupId>de.andrena.tools.nopackagecycles</groupId>
120121
<artifactId>no-package-cycles-enforcer-rule</artifactId>
121-
<version>1.0.3</version>
122+
<version>1.0.4</version>
122123
</dependency>
123124
</dependencies>
124125
<executions>
@@ -194,7 +195,7 @@
194195
<scope>test</scope>
195196
</dependency>
196197
<dependency>
197-
<groupId>org.apache.commons</groupId>
198+
<groupId>commons-io</groupId>
198199
<artifactId>commons-io</artifactId>
199200
<version>1.3.2</version>
200201
<scope>test</scope>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package de.andrena.tools.nopackagecycles;
2+
3+
import static java.util.Collections.unmodifiableList;
4+
5+
import java.io.File;
6+
import java.util.Iterator;
7+
import java.util.LinkedList;
8+
import java.util.List;
9+
10+
import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
11+
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
12+
13+
public class DirectoriesWithClasses implements Iterable<File>{
14+
15+
public static final String MAVEN_PROJECT_BUILD_OUTPUT_DIRECTORY_VAR = "${project.build.outputDirectory}";
16+
public static final String MAVEN_PROJECT_BUILD_TEST_OUTPUT_DIRECTORY_VAR = "${project.build.testOutputDirectory}";
17+
18+
private final List<File> directories = new LinkedList<File>();
19+
20+
public DirectoriesWithClasses(EnforcerRuleHelper helper) throws ExpressionEvaluationException {
21+
addDirectoryIfExists(helper, MAVEN_PROJECT_BUILD_OUTPUT_DIRECTORY_VAR);
22+
addDirectoryIfExists(helper, MAVEN_PROJECT_BUILD_TEST_OUTPUT_DIRECTORY_VAR);
23+
}
24+
25+
private void addDirectoryIfExists(EnforcerRuleHelper helper, String variable)
26+
throws ExpressionEvaluationException {
27+
File directory = new File((String) helper.evaluate(variable));
28+
if(directory.exists()) {
29+
helper.getLog().info("Adding directory " + directory.getAbsolutePath() + " for package cycles search.");
30+
directories.add(directory);
31+
} else {
32+
helper.getLog().info("Directory " + directory.getAbsolutePath() + " could not be found.");
33+
}
34+
}
35+
36+
public boolean directoriesWithClassesFound() {
37+
return !directories.isEmpty();
38+
}
39+
40+
public Iterator<File> iterator() {
41+
return unmodifiableList(directories).iterator();
42+
}
43+
}
Lines changed: 69 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,70 @@
1-
package de.andrena.tools.nopackagecycles;
2-
3-
import java.io.File;
4-
import java.io.IOException;
5-
import java.util.ArrayList;
6-
import java.util.Collection;
7-
8-
import jdepend.framework.JDepend;
9-
import jdepend.framework.JavaPackage;
10-
11-
import org.apache.maven.enforcer.rule.api.EnforcerRule;
12-
import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
13-
import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
14-
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
15-
16-
public class NoPackageCyclesRule implements EnforcerRule {
17-
18-
public static final String MAVEN_CLASSES_DIR = "classes";
19-
public static final String MAVEN_PROJECT_BUILD_DIRECTORY_VAR = "${project.build.directory}";
20-
21-
public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
22-
try {
23-
executePackageCycleCheckIfNecessary(helper);
24-
} catch (ExpressionEvaluationException e) {
25-
throw new EnforcerRuleException("Unable to lookup an expression " + e.getLocalizedMessage(), e);
26-
} catch (IOException e) {
27-
throw new EnforcerRuleException("Unable to access target directory " + e.getLocalizedMessage(), e);
28-
}
29-
}
30-
31-
private void executePackageCycleCheckIfNecessary(EnforcerRuleHelper helper) throws ExpressionEvaluationException,
32-
IOException, EnforcerRuleException {
33-
File targetDir = new File((String) helper.evaluate(MAVEN_PROJECT_BUILD_DIRECTORY_VAR));
34-
File classesDir = new File(targetDir, MAVEN_CLASSES_DIR);
35-
helper.getLog().info("Searching directory " + classesDir.getAbsolutePath() + " for package cycles.");
36-
if (checkIsNecessary(classesDir)) {
37-
executePackageCycleCheck(classesDir);
38-
} else {
39-
helper.getLog().info("Directory " + classesDir.getAbsolutePath() + " could not be found.");
40-
}
41-
}
42-
43-
private void executePackageCycleCheck(File classesDir) throws IOException, EnforcerRuleException {
44-
JDepend jdepend = createJDepend();
45-
jdepend.addDirectory(classesDir.getAbsolutePath());
46-
jdepend.analyze();
47-
if (jdepend.containsCycles()) {
48-
throw new EnforcerRuleException("There are package cycles:" + getPackageCycles(jdepend));
49-
}
50-
}
51-
52-
protected JDepend createJDepend() {
53-
return new JDepend();
54-
}
55-
56-
private String getPackageCycles(JDepend jdepend) {
57-
@SuppressWarnings("unchecked")
58-
Collection<JavaPackage> packages = jdepend.getPackages();
59-
return new PackageCycleOutput(new ArrayList<JavaPackage>(packages)).getOutput();
60-
}
61-
62-
private boolean checkIsNecessary(File classesDir) {
63-
return classesDir.exists();
64-
}
65-
66-
public String getCacheId() {
67-
return "";
68-
}
69-
70-
public boolean isCacheable() {
71-
return false;
72-
}
73-
74-
public boolean isResultValid(EnforcerRule arg0) {
75-
return false;
76-
}
1+
package de.andrena.tools.nopackagecycles;
2+
3+
import java.io.File;
4+
import java.io.IOException;
5+
import java.util.ArrayList;
6+
import java.util.Collection;
7+
8+
import jdepend.framework.JDepend;
9+
import jdepend.framework.JavaPackage;
10+
11+
import org.apache.maven.enforcer.rule.api.EnforcerRule;
12+
import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
13+
import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
14+
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
15+
16+
public class NoPackageCyclesRule implements EnforcerRule {
17+
18+
public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
19+
try {
20+
executePackageCycleCheckIfNecessary(helper);
21+
} catch (ExpressionEvaluationException e) {
22+
throw new EnforcerRuleException("Unable to lookup an expression " + e.getLocalizedMessage(), e);
23+
} catch (IOException e) {
24+
throw new EnforcerRuleException("Unable to access target directory " + e.getLocalizedMessage(), e);
25+
}
26+
}
27+
28+
private void executePackageCycleCheckIfNecessary(EnforcerRuleHelper helper) throws ExpressionEvaluationException,
29+
IOException, EnforcerRuleException {
30+
DirectoriesWithClasses directories = new DirectoriesWithClasses(helper);
31+
if (directories.directoriesWithClassesFound()) {
32+
executePackageCycleCheck(directories);
33+
} else {
34+
helper.getLog().info("No directories with classes to check for cycles found.");
35+
}
36+
}
37+
38+
private void executePackageCycleCheck(Iterable<File> directories) throws IOException, EnforcerRuleException {
39+
JDepend jdepend = createJDepend();
40+
for (File directory : directories) {
41+
jdepend.addDirectory(directory.getAbsolutePath());
42+
}
43+
jdepend.analyze();
44+
if (jdepend.containsCycles()) {
45+
throw new EnforcerRuleException("There are package cycles:" + getPackageCycles(jdepend));
46+
}
47+
}
48+
49+
protected JDepend createJDepend() {
50+
return new JDepend();
51+
}
52+
53+
private String getPackageCycles(JDepend jdepend) {
54+
@SuppressWarnings("unchecked")
55+
Collection<JavaPackage> packages = jdepend.getPackages();
56+
return new PackageCycleOutput(new ArrayList<JavaPackage>(packages)).getOutput();
57+
}
58+
59+
public String getCacheId() {
60+
return "";
61+
}
62+
63+
public boolean isCacheable() {
64+
return false;
65+
}
66+
67+
public boolean isResultValid(EnforcerRule arg0) {
68+
return false;
69+
}
7770
}

src/test/java/de/andrena/tools/nopackagecycles/NoPackageCyclesRuleIntegrationTest.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@
1111
import org.apache.commons.io.IOUtils;
1212
import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
1313
import org.junit.Before;
14-
import org.junit.Rule;
1514
import org.junit.Test;
16-
import org.junit.rules.ExpectedException;
1715

1816
import de.andrena.tools.nopackagecycles.mock.EnforcerRuleHelperMock;
1917

@@ -26,9 +24,6 @@ public class NoPackageCyclesRuleIntegrationTest {
2624
private NoPackageCyclesRule rule;
2725
private EnforcerRuleHelperMock helper;
2826

29-
@Rule
30-
public ExpectedException expectedException = ExpectedException.none();
31-
3227
@Before
3328
public void setUp() throws Exception {
3429
rule = new NoPackageCyclesRule();
@@ -46,7 +41,8 @@ public void junitIntegrationTest() throws Exception {
4641
}
4742

4843
private void assertPackageCycles(URL targetFolder, URL expectedOutput) throws URISyntaxException, IOException {
49-
helper.setTargetDir(new File(targetFolder.toURI()));
44+
helper.setTestClassesDir(new File("non-existent"));
45+
helper.setClassesDir(new File(targetFolder.toURI()));
5046
try {
5147
rule.execute(helper);
5248
fail("expected EnforcerRuleException");

src/test/java/de/andrena/tools/nopackagecycles/NoPackageCyclesRuleTest.java

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ protected JDepend createJDepend() {
4343
public void setUp() throws Exception {
4444
jdependMock = new JDependMock();
4545
rule = new NoPackageCyclesRuleMock();
46-
temporaryFolder.newFolder(NoPackageCyclesRule.MAVEN_CLASSES_DIR);
4746
helper = new EnforcerRuleHelperMock();
48-
helper.setTargetDir(temporaryFolder.getRoot());
47+
helper.setClassesDir(temporaryFolder.newFolder("classes"));
48+
helper.setTestClassesDir(temporaryFolder.newFolder("test-classes"));
4949
}
5050

5151
@Test
@@ -65,13 +65,16 @@ public void result_IsNotValid() {
6565

6666
@Test
6767
public void execute_checkNotNecessary_ClassesDirNotFound() throws Exception {
68-
File newFolder = temporaryFolder.newFolder();
69-
helper.setTargetDir(newFolder);
68+
File nonExistentClassesFolder = new File(temporaryFolder.getRoot(), "non-existent-classes-dir");
69+
helper.setClassesDir(nonExistentClassesFolder);
70+
File nonExistentTestClassesFolder = new File(temporaryFolder.getRoot(), "non-existent-test-classes-dir");
71+
helper.setTestClassesDir(nonExistentTestClassesFolder);
7072
rule.execute(helper);
7173
List<String> infoLogs = helper.getLogMock().getInfo();
72-
assertThat(infoLogs, hasSize(2));
73-
assertSearchingInfo(newFolder, infoLogs);
74-
assertThat(infoLogs.get(1), is("Directory " + getTargetDirectory(newFolder) + " could not be found."));
74+
assertThat(infoLogs, hasSize(3));
75+
assertThat(infoLogs.get(0), is("Directory " + nonExistentClassesFolder.getAbsolutePath() + " could not be found."));
76+
assertThat(infoLogs.get(1), is("Directory " + nonExistentTestClassesFolder.getAbsolutePath() + " could not be found."));
77+
assertThat(infoLogs.get(2), is("No directories with classes to check for cycles found."));
7578
}
7679

7780
@Test
@@ -94,8 +97,20 @@ public void execute_JdependAddDirectoryFailed_ThrowsException() throws Exception
9497
public void execute_ContainsNoCycles() throws Exception {
9598
rule.execute(helper);
9699
List<String> infoLogs = helper.getLogMock().getInfo();
97-
assertThat(infoLogs, hasSize(1));
98-
assertSearchingInfo(temporaryFolder.getRoot(), infoLogs);
100+
assertThat(infoLogs, hasSize(2));
101+
assertThat(infoLogs.get(0), is("Adding directory " + new File(temporaryFolder.getRoot(), "classes").getAbsolutePath() + " for package cycles search."));
102+
assertThat(infoLogs.get(1), is("Adding directory " + new File(temporaryFolder.getRoot(), "test-classes").getAbsolutePath() + " for package cycles search."));
103+
}
104+
105+
@Test
106+
public void execute_ContainsNoCyclesWithoutTestClasses() throws Exception {
107+
File nonExistentTestClassesDir = new File(temporaryFolder.getRoot(), "does not exist");
108+
helper.setTestClassesDir(nonExistentTestClassesDir);
109+
rule.execute(helper);
110+
List<String> infoLogs = helper.getLogMock().getInfo();
111+
assertThat(infoLogs, hasSize(2));
112+
assertThat(infoLogs.get(0), is("Adding directory " + new File(temporaryFolder.getRoot(), "classes").getAbsolutePath() + " for package cycles search."));
113+
assertThat(infoLogs.get(1), is("Directory " + nonExistentTestClassesDir.getAbsolutePath() + " could not be found."));
99114
}
100115

101116
@Test
@@ -105,13 +120,4 @@ public void execute_ContainsCycles() throws Exception {
105120
expectedException.expectMessage(containsString("There are package cycles"));
106121
rule.execute(helper);
107122
}
108-
109-
private void assertSearchingInfo(File projectDirectory, List<String> infoLogs) {
110-
assertThat(infoLogs.get(0), is("Searching directory " + getTargetDirectory(projectDirectory)
111-
+ " for package cycles."));
112-
}
113-
114-
private String getTargetDirectory(File newFolder) {
115-
return new File(newFolder, NoPackageCyclesRule.MAVEN_CLASSES_DIR).getAbsolutePath();
116-
}
117123
}

0 commit comments

Comments
 (0)