Skip to content

Commit 696dcaf

Browse files
committed
added target/test-classes directory to check for cycles
This enables package cycle check between test and src folder. To add test folder the maven phase has to be changed to test-compile
1 parent 8051a76 commit 696dcaf

File tree

6 files changed

+129
-71
lines changed

6 files changed

+129
-71
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).
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+
}

src/main/java/de/andrena/tools/nopackagecycles/NoPackageCyclesRule.java

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515

1616
public class NoPackageCyclesRule implements EnforcerRule {
1717

18-
public static final String MAVEN_PROJECT_BUILD_OUTPUT_DIRECTORY_VAR = "${project.build.outputDirectory}";
19-
2018
public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
2119
try {
2220
executePackageCycleCheckIfNecessary(helper);
@@ -29,18 +27,19 @@ public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
2927

3028
private void executePackageCycleCheckIfNecessary(EnforcerRuleHelper helper) throws ExpressionEvaluationException,
3129
IOException, EnforcerRuleException {
32-
File classesDir = new File((String) helper.evaluate(MAVEN_PROJECT_BUILD_OUTPUT_DIRECTORY_VAR));
33-
helper.getLog().info("Searching directory " + classesDir.getAbsolutePath() + " for package cycles.");
34-
if (checkIsNecessary(classesDir)) {
35-
executePackageCycleCheck(classesDir);
30+
DirectoriesWithClasses directories = new DirectoriesWithClasses(helper);
31+
if (directories.directoriesWithClassesFound()) {
32+
executePackageCycleCheck(directories);
3633
} else {
37-
helper.getLog().info("Directory " + classesDir.getAbsolutePath() + " could not be found.");
34+
helper.getLog().info("No directories with classes to check for cycles found.");
3835
}
3936
}
4037

41-
private void executePackageCycleCheck(File classesDir) throws IOException, EnforcerRuleException {
38+
private void executePackageCycleCheck(Iterable<File> directories) throws IOException, EnforcerRuleException {
4239
JDepend jdepend = createJDepend();
43-
jdepend.addDirectory(classesDir.getAbsolutePath());
40+
for (File directory : directories) {
41+
jdepend.addDirectory(directory.getAbsolutePath());
42+
}
4443
jdepend.analyze();
4544
if (jdepend.containsCycles()) {
4645
throw new EnforcerRuleException("There are package cycles:" + getPackageCycles(jdepend));
@@ -57,10 +56,6 @@ private String getPackageCycles(JDepend jdepend) {
5756
return new PackageCycleOutput(new ArrayList<JavaPackage>(packages)).getOutput();
5857
}
5958

60-
private boolean checkIsNecessary(File classesDir) {
61-
return classesDir.exists();
62-
}
63-
6459
public String getCacheId() {
6560
return "";
6661
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ public void junitIntegrationTest() throws Exception {
4141
}
4242

4343
private void assertPackageCycles(URL targetFolder, URL expectedOutput) throws URISyntaxException, IOException {
44-
helper.setTargetDir(new File(targetFolder.toURI()));
44+
helper.setTestClassesDir(new File("non-existent"));
45+
helper.setClassesDir(new File(targetFolder.toURI()));
4546
try {
4647
rule.execute(helper);
4748
fail("expected EnforcerRuleException");

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

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ public void setUp() throws Exception {
4444
jdependMock = new JDependMock();
4545
rule = new NoPackageCyclesRuleMock();
4646
helper = new EnforcerRuleHelperMock();
47-
helper.setTargetDir(temporaryFolder.getRoot());
47+
helper.setClassesDir(temporaryFolder.newFolder("classes"));
48+
helper.setTestClassesDir(temporaryFolder.newFolder("test-classes"));
4849
}
4950

5051
@Test
@@ -64,13 +65,16 @@ public void result_IsNotValid() {
6465

6566
@Test
6667
public void execute_checkNotNecessary_ClassesDirNotFound() throws Exception {
67-
File nonExistentFolder = new File(temporaryFolder.getRoot(), "non-existent-classes-dir");
68-
helper.setTargetDir(nonExistentFolder);
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);
6972
rule.execute(helper);
7073
List<String> infoLogs = helper.getLogMock().getInfo();
71-
assertThat(infoLogs, hasSize(2));
72-
assertSearchingInfo(nonExistentFolder, infoLogs);
73-
assertThat(infoLogs.get(1), is("Directory " + nonExistentFolder.getAbsolutePath() + " 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."));
7478
}
7579

7680
@Test
@@ -93,8 +97,20 @@ public void execute_JdependAddDirectoryFailed_ThrowsException() throws Exception
9397
public void execute_ContainsNoCycles() throws Exception {
9498
rule.execute(helper);
9599
List<String> infoLogs = helper.getLogMock().getInfo();
96-
assertThat(infoLogs, hasSize(1));
97-
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."));
98114
}
99115

100116
@Test
@@ -104,9 +120,4 @@ public void execute_ContainsCycles() throws Exception {
104120
expectedException.expectMessage(containsString("There are package cycles"));
105121
rule.execute(helper);
106122
}
107-
108-
private void assertSearchingInfo(File projectDirectory, List<String> infoLogs) {
109-
assertThat(infoLogs.get(0), is("Searching directory " + projectDirectory.getAbsolutePath()
110-
+ " for package cycles."));
111-
}
112123
}

src/test/java/de/andrena/tools/nopackagecycles/mock/EnforcerRuleHelperMock.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@
1010
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
1111
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
1212

13-
import de.andrena.tools.nopackagecycles.NoPackageCyclesRule;
13+
import de.andrena.tools.nopackagecycles.DirectoriesWithClasses;
1414

1515
public class EnforcerRuleHelperMock implements EnforcerRuleHelper {
1616

17-
private File targetDir;
17+
private File classesDir;
18+
private File testClassesDir;
1819
private boolean evaluateThrowsException;
1920
private final LogMock logMock = new LogMock();
2021

@@ -26,10 +27,14 @@ public void setEvaluateThrowsException(boolean evaluateThrowsException) {
2627
this.evaluateThrowsException = evaluateThrowsException;
2728
}
2829

29-
public void setTargetDir(File targetDir) {
30-
this.targetDir = targetDir;
30+
public void setClassesDir(File targetDir) {
31+
this.classesDir = targetDir;
3132
}
3233

34+
public void setTestClassesDir(File testClassesDir) {
35+
this.testClassesDir = testClassesDir;
36+
}
37+
3338
public File alignToBaseDirectory(File arg0) {
3439
return null;
3540
}
@@ -38,8 +43,11 @@ public Object evaluate(String variable) throws ExpressionEvaluationException {
3843
if (evaluateThrowsException) {
3944
throw new ExpressionEvaluationException("");
4045
}
41-
if (NoPackageCyclesRule.MAVEN_PROJECT_BUILD_OUTPUT_DIRECTORY_VAR.equals(variable)) {
42-
return targetDir.getPath();
46+
if (DirectoriesWithClasses.MAVEN_PROJECT_BUILD_OUTPUT_DIRECTORY_VAR.equals(variable)) {
47+
return classesDir.getPath();
48+
}
49+
if (DirectoriesWithClasses.MAVEN_PROJECT_BUILD_TEST_OUTPUT_DIRECTORY_VAR.equals(variable)) {
50+
return testClassesDir.getPath();
4351
}
4452
return null;
4553
}

0 commit comments

Comments
 (0)