diff --git a/nebula-archrules-core/src/main/java/com/netflix/nebula/archrules/core/Runner.java b/nebula-archrules-core/src/main/java/com/netflix/nebula/archrules/core/Runner.java index ac7ad78..b7d64c5 100644 --- a/nebula-archrules-core/src/main/java/com/netflix/nebula/archrules/core/Runner.java +++ b/nebula-archrules-core/src/main/java/com/netflix/nebula/archrules/core/Runner.java @@ -2,11 +2,27 @@ import com.tngtech.archunit.core.domain.JavaClasses; import com.tngtech.archunit.core.importer.ClassFileImporter; +import com.tngtech.archunit.core.importer.Location; +import com.tngtech.archunit.core.importer.Locations; import com.tngtech.archunit.lang.ArchRule; import com.tngtech.archunit.lang.ConditionEvents; import com.tngtech.archunit.lang.EvaluationResult; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.util.*; +import java.util.stream.Collectors; + public class Runner { + /** + * Check a rule against some classes. + * This can be invoked from the real Gradle plugin or unit tests for rules to ensure the same logic is observed there. + * + * @param rule the rule to run + * @param classesToCheck the classes to run the rule against + * @return the result, which contains information about failure + */ public static EvaluationResult check(ArchRule rule, JavaClasses classesToCheck) { try { return rule.evaluate(classesToCheck); @@ -24,16 +40,35 @@ public static EvaluationResult check(ArchRule rule, JavaClasses classesToCheck) } /** - * Check a rule against some classes. - * This can be invoked from the real Gradle plugin or unit tests for rules to ensure the same logic is observed there. + * Check a rule against some classes and their package-info + * This intended to be used from unit tests for rules to ensure the same logic is observed there. * * @param rule the rule to run * @param classesToCheck the classes to run the rule against * @return the result, which contains information about failure */ public static EvaluationResult check(ArchRule rule, Class... classesToCheck) { + Set locs = Arrays.stream(classesToCheck) + .map(Locations::ofClass) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + List uris = Arrays.stream(classesToCheck) + .map(clazz -> clazz.getPackage().getName()) + .map(Locations::ofPackage) + .flatMap(it -> it.stream().map(Location::asURI)) + .map(u -> URI.create(u.toASCIIString() + "package-info.class")) + .map(uri -> { + try { + return uri.toURL(); + } catch (MalformedURLException e) { + return null; + } + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + locs.addAll(Locations.of(uris)); final JavaClasses classes = new ClassFileImporter() - .importClasses(classesToCheck); + .importLocations(locs); return check(rule, classes); } } diff --git a/nebula-archrules-core/src/test/java/com/netflix/nebula/archrules/core/RunnerTest.java b/nebula-archrules-core/src/test/java/com/netflix/nebula/archrules/core/RunnerTest.java index 964dc24..6045f8a 100644 --- a/nebula-archrules-core/src/test/java/com/netflix/nebula/archrules/core/RunnerTest.java +++ b/nebula-archrules-core/src/test/java/com/netflix/nebula/archrules/core/RunnerTest.java @@ -1,8 +1,13 @@ package com.netflix.nebula.archrules.core; +import com.netflix.nebula.archrules.testpackage.TestDeprecated; +import com.tngtech.archunit.core.domain.JavaClass; +import com.tngtech.archunit.lang.ArchCondition; import com.tngtech.archunit.lang.ArchRule; +import com.tngtech.archunit.lang.ConditionEvents; import com.tngtech.archunit.lang.EvaluationResult; import com.tngtech.archunit.lang.Priority; +import com.tngtech.archunit.lang.SimpleConditionEvent; import com.tngtech.archunit.lang.syntax.ArchRuleDefinition; import org.junit.jupiter.api.Test; @@ -10,6 +15,9 @@ import static org.assertj.core.api.Assertions.assertThat; public class RunnerTest { + private final ArchRule noDeprecatedRule = ArchRuleDefinition.classes().should() + .notBeAnnotatedWith(Deprecated.class); + @Test public void test_pass() { final EvaluationResult result = Runner.check(noDeprecatedRule, PassingClass.class); @@ -36,8 +44,6 @@ static class PassingClass { static class FailingClass { } - private final ArchRule noDeprecatedRule = ArchRuleDefinition.classes().should() - .notBeAnnotatedWith(Deprecated.class); private final ArchRule smokeTestRule = ArchRuleDefinition.priority(Priority.MEDIUM) .classes().that(simpleName("SmokeTest")) .should().beAnnotatedWith(Deprecated.class) @@ -63,4 +69,25 @@ public void test_smoke_fail() { assertThat(result.getFailureReport().getDetails()) .contains(NoClassesMatchedEvent.NO_MATCH_MESSAGE); } + + private final ArchCondition notBeInDeprecatedPackage = + new ArchCondition("not be in a package marked with @Deprecated") { + @Override + public void check(JavaClass javaClass, ConditionEvents events) { + boolean isInDeprecatedPackage = javaClass.getPackage().getPackageInfo().isAnnotatedWith(Deprecated.class); + if (isInDeprecatedPackage) { + String message = String.format("Class %s is in a package marked with @Deprecated", javaClass.getName()); + events.add(SimpleConditionEvent.violated(javaClass, message)); + } + } + }; + private final ArchRule noDeprecatedPackageRule = ArchRuleDefinition + .classes().should(notBeInDeprecatedPackage); + + @Test + public void test_package_deprecated_rule() { + final EvaluationResult result = Runner.check(noDeprecatedPackageRule, TestDeprecated.class); + assertThat(result.hasViolation()).isTrue(); + } + } diff --git a/nebula-archrules-core/src/test/java/com/netflix/nebula/archrules/testpackage/TestDeprecated.java b/nebula-archrules-core/src/test/java/com/netflix/nebula/archrules/testpackage/TestDeprecated.java new file mode 100644 index 0000000..60e99be --- /dev/null +++ b/nebula-archrules-core/src/test/java/com/netflix/nebula/archrules/testpackage/TestDeprecated.java @@ -0,0 +1,4 @@ +package com.netflix.nebula.archrules.testpackage; + +public class TestDeprecated { +} diff --git a/nebula-archrules-core/src/test/java/com/netflix/nebula/archrules/testpackage/package-info.java b/nebula-archrules-core/src/test/java/com/netflix/nebula/archrules/testpackage/package-info.java new file mode 100644 index 0000000..93bc428 --- /dev/null +++ b/nebula-archrules-core/src/test/java/com/netflix/nebula/archrules/testpackage/package-info.java @@ -0,0 +1,2 @@ +@Deprecated +package com.netflix.nebula.archrules.testpackage; \ No newline at end of file diff --git a/nebula-archrules-gradle-plugin/gradle.lockfile b/nebula-archrules-gradle-plugin/gradle.lockfile index 953dafd..dcde249 100644 --- a/nebula-archrules-gradle-plugin/gradle.lockfile +++ b/nebula-archrules-gradle-plugin/gradle.lockfile @@ -4,10 +4,10 @@ cglib:cglib-nodep:3.2.2=testRuntimeClasspath com.fasterxml.jackson.core:jackson-annotations:2.20=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath com.jayway.jsonpath:json-path:2.9.0=testCompileClasspath,testRuntimeClasspath -com.netflix.nebula:archrules-deprecation:0.3.0=archRules -com.netflix.nebula:archrules-joda:0.3.0=archRules -com.netflix.nebula:archrules-testing-frameworks:0.3.0=archRules -com.netflix.nebula:nebula-archrules-core:0.2.3=archRules +com.netflix.nebula:archrules-deprecation:0.4.0=archRules +com.netflix.nebula:archrules-joda:0.4.0=archRules +com.netflix.nebula:archrules-testing-frameworks:0.4.0=archRules +com.netflix.nebula:nebula-archrules-core:0.3.0=archRules com.netflix.nebula:nebula-test:11.9.0=testCompileClasspath,testRuntimeClasspath com.tngtech.archunit:archunit:1.4.1=archRules,compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath net.bytebuddy:byte-buddy:1.17.7=testCompileClasspath,testRuntimeClasspath