diff --git a/README.md b/README.md index d1dfee4..dfc01ac 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,15 @@ This repository contains several libraries of ArchRules which can be used in pro [![Maven Central](https://img.shields.io/maven-central/v/com.netflix.nebula/archrules-deprecation?style=for-the-badge&color=01AF01)](https://repo1.maven.org/maven2/com/netflix/nebula/archrules-deprecation/) ## Gradle Plugin Development -[![Maven Central](https://img.shields.io/maven-central/v/com.netflix.nebula/archrules-gradle-plugin-development?style=for-the-badge&color=01AF01)](https://repo1.maven.org/maven2/com/netflix/nebula/gradle-plugin-development/) +[![Maven Central](https://img.shields.io/maven-central/v/com.netflix.nebula/archrules-gradle-plugin-development?style=for-the-badge&color=01AF01)](https://repo1.maven.org/maven2/com/netflix/nebula/archrules-gradle-plugin-development/) These rules enforce best practices when developing Gradle plugins. +## Guava Rules +[![Maven Central](https://img.shields.io/maven-central/v/com.netflix.nebula/archrules-guava?style=for-the-badge&color=01AF01)](https://repo1.maven.org/maven2/com/netflix/nebula/archrules-guava/) + +These rules detect the usage of certain APIs from Guava which have standard library replacements. + ## Javax Rules [![Maven Central](https://img.shields.io/maven-central/v/com.netflix.nebula/archrules-joda?style=for-the-badge&color=01AF01)](https://repo1.maven.org/maven2/com/netflix/nebula/archrules-javax/) diff --git a/archrules-deprecation/gradle.lockfile b/archrules-deprecation/gradle.lockfile index c434cfd..a22781c 100644 --- a/archrules-deprecation/gradle.lockfile +++ b/archrules-deprecation/gradle.lockfile @@ -3,16 +3,12 @@ # This file is expected to be part of source control. ch.qos.logback:logback-classic:1.5.20=archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath ch.qos.logback:logback-core:1.5.20=archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath -com.netflix.nebula:archrules-joda:0.3.0=archRules -com.netflix.nebula:archrules-joda:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime -com.netflix.nebula:archrules-nullability:0.3.0=archRules -com.netflix.nebula:archrules-nullability:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime -com.netflix.nebula:archrules-testing-frameworks:0.3.0=archRules -com.netflix.nebula:archrules-testing-frameworks:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime -com.netflix.nebula:nebula-archrules-core:0.2.3=archRules -com.netflix.nebula:nebula-archrules-core:0.3.0=archRulesRuntimeClasspath -com.netflix.nebula:nebula-archrules-core:0.4.0=mainArchRulesRuntime,testArchRulesRuntime -com.netflix.nebula:nebula-archrules-core:0.5.3=archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath +com.netflix.nebula:archrules-joda:0.6.0=archRules,archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime +com.netflix.nebula:archrules-nullability:0.6.0=archRules,archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime +com.netflix.nebula:archrules-security:0.6.0=archRules,archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime +com.netflix.nebula:archrules-testing-frameworks:0.6.0=archRules,archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime +com.netflix.nebula:nebula-archrules-core:0.5.2=archRules,mainArchRulesRuntime,testArchRulesRuntime +com.netflix.nebula:nebula-archrules-core:0.5.5=archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesRuntimeClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath com.tngtech.archunit:archunit:1.4.1=archRules,archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesRuntimeClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath,mainArchRulesRuntime,testArchRulesRuntime net.bytebuddy:byte-buddy:1.17.7=archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath org.apiguardian:apiguardian-api:1.1.2=archRulesTestCompileClasspath diff --git a/archrules-gradle-plugin-development/gradle.lockfile b/archrules-gradle-plugin-development/gradle.lockfile index 25e49ea..c9ac4d4 100644 --- a/archrules-gradle-plugin-development/gradle.lockfile +++ b/archrules-gradle-plugin-development/gradle.lockfile @@ -3,23 +3,18 @@ # This file is expected to be part of source control. ch.qos.logback:logback-classic:1.5.20=archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath ch.qos.logback:logback-core:1.5.20=archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath -com.netflix.nebula:archrules-deprecation:0.4.0=archRules com.netflix.nebula:archrules-deprecation:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime -com.netflix.nebula:archrules-joda:0.4.0=archRules com.netflix.nebula:archrules-joda:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime -com.netflix.nebula:archrules-nullability:0.4.0=archRules com.netflix.nebula:archrules-nullability:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime -com.netflix.nebula:archrules-testing-frameworks:0.4.0=archRules +com.netflix.nebula:archrules-security:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime com.netflix.nebula:archrules-testing-frameworks:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime -com.netflix.nebula:nebula-archrules-core:0.3.0=archRules -com.netflix.nebula:nebula-archrules-core:0.4.0=mainArchRulesRuntime,testArchRulesRuntime -com.netflix.nebula:nebula-archrules-core:0.5.2=archRulesRuntimeClasspath -com.netflix.nebula:nebula-archrules-core:0.5.3=archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath -com.tngtech.archunit:archunit:1.4.1=archRules,archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesRuntimeClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath,mainArchRulesRuntime,testArchRulesRuntime +com.netflix.nebula:nebula-archrules-core:0.5.2=mainArchRulesRuntime,testArchRulesRuntime +com.netflix.nebula:nebula-archrules-core:0.5.5=archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath +com.tngtech.archunit:archunit:1.4.1=archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath,mainArchRulesRuntime,testArchRulesRuntime net.bytebuddy:byte-buddy:1.17.7=archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath org.apiguardian:apiguardian-api:1.1.2=archRulesTestCompileClasspath org.assertj:assertj-core:3.27.6=archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath -org.jspecify:jspecify:1.0.0=archRules,archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesRuntimeClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath,mainArchRulesRuntime,testArchRulesRuntime +org.jspecify:jspecify:1.0.0=archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath,mainArchRulesRuntime,testArchRulesRuntime org.junit.jupiter:junit-jupiter-api:5.12.2=archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath org.junit.jupiter:junit-jupiter-engine:5.12.2=archRulesTestArchRulesRuntime,archRulesTestRuntimeClasspath org.junit.jupiter:junit-jupiter-params:5.12.2=archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath @@ -29,5 +24,5 @@ org.junit.platform:junit-platform-engine:1.12.2=archRulesTestArchRulesRuntime,ar org.junit.platform:junit-platform-launcher:1.12.2=archRulesTestArchRulesRuntime,archRulesTestRuntimeClasspath org.junit:junit-bom:5.12.2=archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath org.opentest4j:opentest4j:1.3.0=archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath -org.slf4j:slf4j-api:2.0.17=archRules,archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesRuntimeClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath,mainArchRulesRuntime,testArchRulesRuntime -empty=annotationProcessor,archRulesAnnotationProcessor,archRulesTestAnnotationProcessor,compileClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath +org.slf4j:slf4j-api:2.0.17=archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath,mainArchRulesRuntime,testArchRulesRuntime +empty=annotationProcessor,archRulesAnnotationProcessor,archRulesTestAnnotationProcessor,compileClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath diff --git a/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/ContainAnyMembersInClassHierarchyThatPredicate.java b/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/ContainAnyMembersInClassHierarchyThatPredicate.java new file mode 100644 index 0000000..ca4ce2f --- /dev/null +++ b/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/ContainAnyMembersInClassHierarchyThatPredicate.java @@ -0,0 +1,26 @@ +package com.netflix.nebula.archrules.gradleplugins; + +import com.tngtech.archunit.base.DescribedPredicate; +import com.tngtech.archunit.core.domain.JavaClass; +import com.tngtech.archunit.core.domain.JavaMember; +import org.jspecify.annotations.NullMarked; + +import java.util.Set; +import java.util.function.Function; + +@NullMarked +public class ContainAnyMembersInClassHierarchyThatPredicate extends DescribedPredicate { + private final Function> getMembers; + private final DescribedPredicate predicate; + + ContainAnyMembersInClassHierarchyThatPredicate(String memberDescription, Function> getMembers, DescribedPredicate predicate) { + super("contain any " + memberDescription + " that " + predicate.getDescription()); + this.getMembers = getMembers; + this.predicate = predicate; + } + + @Override + public boolean test(JavaClass input) { + return getMembers.apply(input).stream().anyMatch(predicate); + } +} diff --git a/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleDeprecatedApiRule.java b/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleDeprecatedApiRule.java index 8b83996..71b6115 100644 --- a/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleDeprecatedApiRule.java +++ b/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleDeprecatedApiRule.java @@ -1,18 +1,13 @@ package com.netflix.nebula.archrules.gradleplugins; -import com.netflix.nebula.archrules.core.ArchRulesService; -import com.tngtech.archunit.core.domain.JavaAccess; -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.Priority; -import com.tngtech.archunit.lang.SimpleConditionEvent; import com.tngtech.archunit.lang.syntax.ArchRuleDefinition; import org.jspecify.annotations.NullMarked; -import java.util.HashMap; -import java.util.Map; +import static com.netflix.nebula.archrules.gradleplugins.Predicates.accessDeprecatedGradleApi; +import static com.netflix.nebula.archrules.gradleplugins.Predicates.deprecatedGradleClass; +import static com.tngtech.archunit.lang.conditions.ArchConditions.accessTargetWhere; /** * Rules to prevent usage of deprecated Gradle APIs. @@ -20,9 +15,7 @@ * Using deprecated Gradle APIs will cause build failures in future Gradle versions. */ @NullMarked -public class GradleDeprecatedApiRule implements ArchRulesService { - - private static final String GRADLE_API_PACKAGE = "org.gradle"; +public class GradleDeprecatedApiRule { /** * Prevents plugins from using deprecated Gradle APIs. @@ -32,9 +25,10 @@ public class GradleDeprecatedApiRule implements ArchRulesService { * upgrade guides. */ public static final ArchRule pluginsShouldNotUseDeprecatedGradleApis = ArchRuleDefinition.priority(Priority.MEDIUM) - .classes() + .noClasses() .that().implement("org.gradle.api.Plugin") - .should(notUseDeprecatedGradleApis()) + .should().dependOnClassesThat(deprecatedGradleClass) + .orShould(accessTargetWhere(accessDeprecatedGradleApi)) .allowEmptyShould(true) .because( "Plugins should not use deprecated Gradle APIs as they will be removed in future versions. " + @@ -50,52 +44,15 @@ public class GradleDeprecatedApiRule implements ArchRulesService { * upgrade guides. */ public static final ArchRule tasksShouldNotUseDeprecatedGradleApis = ArchRuleDefinition.priority(Priority.MEDIUM) - .classes() + .noClasses() .that().areAssignableTo("org.gradle.api.Task") .and().areNotInterfaces() - .should(notUseDeprecatedGradleApis()) + .should().dependOnClassesThat(deprecatedGradleClass) + .orShould(accessTargetWhere(accessDeprecatedGradleApi)) .allowEmptyShould(true) .because( "Tasks should not use deprecated Gradle APIs as they will be removed in future versions. " + "Consult Gradle upgrade guides for modern alternatives. " + "See https://docs.gradle.org/current/userguide/upgrading_version_8.html" ); - - private static ArchCondition notUseDeprecatedGradleApis() { - return new ArchCondition("not use deprecated Gradle APIs") { - @Override - public void check(JavaClass javaClass, ConditionEvents events) { - for (JavaAccess access : javaClass.getAccessesFromSelf()) { - if (isDeprecatedGradleApi(access)) { - String message = String.format( - "Class %s uses deprecated Gradle API: %s. " + - "This API will be removed in a future Gradle version. " + - "Consult Gradle upgrade guides for alternatives.", - javaClass.getSimpleName(), - access.getDescription() - ); - events.add(SimpleConditionEvent.violated(access, message)); - } - } - } - - private boolean isDeprecatedGradleApi(JavaAccess access) { - String targetOwnerName = access.getTargetOwner().getName(); - - if (!targetOwnerName.startsWith(GRADLE_API_PACKAGE)) { - return false; - } - - return access.getTarget().isAnnotatedWith(Deprecated.class); - } - }; - } - - @Override - public Map getRules() { - Map rules = new HashMap<>(); - rules.put("gradle-plugin-no-deprecated-apis", pluginsShouldNotUseDeprecatedGradleApis); - rules.put("gradle-task-no-deprecated-apis", tasksShouldNotUseDeprecatedGradleApis); - return rules; - } } diff --git a/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleInternalApiRule.java b/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleInternalApiRule.java index 2a129a2..b667062 100644 --- a/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleInternalApiRule.java +++ b/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleInternalApiRule.java @@ -1,18 +1,12 @@ package com.netflix.nebula.archrules.gradleplugins; -import com.netflix.nebula.archrules.core.ArchRulesService; -import com.tngtech.archunit.core.domain.JavaAccess; -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.Priority; -import com.tngtech.archunit.lang.SimpleConditionEvent; import com.tngtech.archunit.lang.syntax.ArchRuleDefinition; import org.jspecify.annotations.NullMarked; -import java.util.HashMap; -import java.util.Map; +import static com.netflix.nebula.archrules.gradleplugins.Predicates.internalGradleClass; +import static com.tngtech.archunit.core.domain.JavaAccess.Predicates.targetOwner; /** * Rules to prevent usage of internal Gradle APIs. @@ -21,10 +15,7 @@ * or be removed without notice between Gradle versions. */ @NullMarked -public class GradleInternalApiRule implements ArchRulesService { - - private static final String GRADLE_PACKAGE = "org.gradle"; - private static final String INTERNAL_PACKAGE_MARKER = ".internal."; +public class GradleInternalApiRule { /** * Prevents plugins from using internal Gradle APIs. @@ -33,10 +24,11 @@ public class GradleInternalApiRule implements ArchRulesService { * and may change or be removed between versions without notice. Use only public * Gradle APIs to ensure compatibility across Gradle versions. */ - public static final ArchRule pluginsShouldNotUseInternalGradleApis = ArchRuleDefinition.priority(Priority.HIGH) - .classes() + public static final ArchRule PLUGIN_INTERNAL = ArchRuleDefinition.priority(Priority.MEDIUM) + .noClasses() .that().implement("org.gradle.api.Plugin") - .should(notUseInternalGradleApis()) + .should().dependOnClassesThat(internalGradleClass) + .orShould().accessTargetWhere(targetOwner(internalGradleClass)) .allowEmptyShould(true) .because( "Plugins should not use internal Gradle APIs (packages containing '.internal.'). " + @@ -51,49 +43,16 @@ public class GradleInternalApiRule implements ArchRulesService { * and may change or be removed between versions without notice. Use only public * Gradle APIs to ensure compatibility across Gradle versions. */ - public static final ArchRule tasksShouldNotUseInternalGradleApis = ArchRuleDefinition.priority(Priority.HIGH) - .classes() + public static final ArchRule TASK_INTERNAL = ArchRuleDefinition.priority(Priority.MEDIUM) + .noClasses() .that().areAssignableTo("org.gradle.api.Task") .and().areNotInterfaces() - .should(notUseInternalGradleApis()) + .should().dependOnClassesThat(internalGradleClass) + .orShould().accessTargetWhere(targetOwner(internalGradleClass)) .allowEmptyShould(true) .because( "Tasks should not use internal Gradle APIs (packages containing '.internal.'). " + "Internal APIs are not stable and may change or be removed without notice. " + "Use only public Gradle APIs documented at https://docs.gradle.org/current/javadoc/" ); - - private static ArchCondition notUseInternalGradleApis() { - return new ArchCondition("not use internal Gradle APIs") { - @Override - public void check(JavaClass javaClass, ConditionEvents events) { - for (JavaAccess access : javaClass.getAccessesFromSelf()) { - if (isInternalGradleApi(access)) { - String message = String.format( - "Class %s uses internal Gradle API: %s. " + - "Internal APIs (packages containing '.internal.') are not stable and may change without notice. " + - "Use public Gradle APIs instead.", - javaClass.getSimpleName(), - access.getDescription() - ); - events.add(SimpleConditionEvent.violated(access, message)); - } - } - } - - private boolean isInternalGradleApi(JavaAccess access) { - String targetPackage = access.getTargetOwner().getPackageName(); - return targetPackage.startsWith(GRADLE_PACKAGE) && - targetPackage.contains(INTERNAL_PACKAGE_MARKER); - } - }; - } - - @Override - public Map getRules() { - Map rules = new HashMap<>(); - rules.put("gradle-plugin-no-internal-apis", pluginsShouldNotUseInternalGradleApis); - rules.put("gradle-task-no-internal-apis", tasksShouldNotUseInternalGradleApis); - return rules; - } } diff --git a/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradlePluginBestPractices.java b/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradlePluginBestPractices.java new file mode 100644 index 0000000..9a0640b --- /dev/null +++ b/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradlePluginBestPractices.java @@ -0,0 +1,43 @@ +package com.netflix.nebula.archrules.gradleplugins; + +import com.netflix.nebula.archrules.core.ArchRulesService; +import com.tngtech.archunit.lang.ArchRule; +import org.jspecify.annotations.NullMarked; + +import java.util.HashMap; +import java.util.Map; + +import static com.netflix.nebula.archrules.gradleplugins.GradleDeprecatedApiRule.pluginsShouldNotUseDeprecatedGradleApis; +import static com.netflix.nebula.archrules.gradleplugins.GradleDeprecatedApiRule.tasksShouldNotUseDeprecatedGradleApis; +import static com.netflix.nebula.archrules.gradleplugins.GradleInternalApiRule.PLUGIN_INTERNAL; +import static com.netflix.nebula.archrules.gradleplugins.GradleInternalApiRule.TASK_INTERNAL; +import static com.netflix.nebula.archrules.gradleplugins.GradlePluginLazyTaskRegistrationRule.LAZY_TASK_CREATION; +import static com.netflix.nebula.archrules.gradleplugins.GradleTaskActionRule.taskActionShouldNotAccessProject; +import static com.netflix.nebula.archrules.gradleplugins.GradleTaskActionRule.taskActionShouldNotCallGetTaskDependencies; +import static com.netflix.nebula.archrules.gradleplugins.GradleTaskCacheabilityRule.FIELDS_PATH_SENSITIVITY; +import static com.netflix.nebula.archrules.gradleplugins.GradleTaskCacheabilityRule.METHODS_PATH_SENSITIVITY; +import static com.netflix.nebula.archrules.gradleplugins.GradleTaskInputOutputRule.INPUTS_OUTPUTS; +import static com.netflix.nebula.archrules.gradleplugins.GradleTaskProviderApiRule.ABSTRACT_GETTERS; +import static com.netflix.nebula.archrules.gradleplugins.GradleTaskProviderApiRule.PROVIDER_PROPERTIES; + +@NullMarked +@SuppressWarnings("unused") +public class GradlePluginBestPractices implements ArchRulesService { + @Override + public Map getRules() { + Map rules = new HashMap<>(); + rules.put("provider properties", PROVIDER_PROPERTIES); + rules.put("abstract getters", ABSTRACT_GETTERS); + rules.put("task project access", taskActionShouldNotAccessProject); + rules.put("task dependencies", taskActionShouldNotCallGetTaskDependencies); + rules.put("lazy task registration", LAZY_TASK_CREATION); + rules.put("Plugin using deprecated gradle APIs", pluginsShouldNotUseDeprecatedGradleApis); + rules.put("Task using deprecated gradle APIs", tasksShouldNotUseDeprecatedGradleApis); + rules.put("Plugin using internal gradle APIs", PLUGIN_INTERNAL); + rules.put("Task using internal gradle APIs", TASK_INTERNAL); + rules.put("Task declares inputs and/or outputs", INPUTS_OUTPUTS); + rules.put("Cacheable Task input field path sensitivity", FIELDS_PATH_SENSITIVITY); + rules.put("Cacheable Task input method path sensitivity", METHODS_PATH_SENSITIVITY); + return rules; + } +} diff --git a/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradlePluginLazyTaskRegistrationRule.java b/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradlePluginLazyTaskRegistrationRule.java index a8b498f..84e55f6 100644 --- a/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradlePluginLazyTaskRegistrationRule.java +++ b/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradlePluginLazyTaskRegistrationRule.java @@ -1,21 +1,11 @@ package com.netflix.nebula.archrules.gradleplugins; -import com.netflix.nebula.archrules.core.ArchRulesService; -import com.tngtech.archunit.core.domain.JavaMethodCall; -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.Priority; -import com.tngtech.archunit.lang.SimpleConditionEvent; import com.tngtech.archunit.lang.syntax.ArchRuleDefinition; import org.jspecify.annotations.NullMarked; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import static com.netflix.nebula.archrules.gradleplugins.Predicates.taskIsCreatedEagerly; /** * Rules for Gradle plugin classes to ensure they use lazy task registration. @@ -25,12 +15,8 @@ * in large multi-module projects. */ @NullMarked -public class GradlePluginLazyTaskRegistrationRule implements ArchRulesService { +class GradlePluginLazyTaskRegistrationRule { - private static final Set EAGER_TASK_CREATION_METHODS = new HashSet<>(Arrays.asList( - "task", - "create" - )); /** * Prevents Plugin classes from using eager task creation methods. @@ -39,10 +25,10 @@ public class GradlePluginLazyTaskRegistrationRule implements ArchRulesService { * all tasks during configuration phase, even if they won't be executed. * Use {@code tasks.register()} instead for lazy task creation. */ - public static final ArchRule pluginsShouldUseLazyTaskRegistration = ArchRuleDefinition.priority(Priority.MEDIUM) - .classes() + static final ArchRule LAZY_TASK_CREATION = ArchRuleDefinition.priority(Priority.MEDIUM) + .noClasses() .that().implement("org.gradle.api.Plugin") - .should(useLazyTaskRegistration()) + .should().callMethodWhere(taskIsCreatedEagerly) .allowEmptyShould(true) .because( "Plugins should use tasks.register() instead of task() or tasks.create() for lazy task registration. " + @@ -50,44 +36,4 @@ public class GradlePluginLazyTaskRegistrationRule implements ArchRulesService { "Lazy registration with tasks.register() only creates tasks when needed. " + "See https://docs.gradle.org/current/userguide/task_configuration_avoidance.html" ); - - private static ArchCondition useLazyTaskRegistration() { - return new ArchCondition("use lazy task registration (tasks.register())") { - @Override - public void check(JavaClass pluginClass, ConditionEvents events) { - pluginClass.getMethodCallsFromSelf().forEach(call -> { - if (isEagerTaskCreation(call)) { - String message = String.format( - "Plugin %s uses eager task creation with %s.%s() at %s. " + - "Use tasks.register() instead for lazy task registration.", - pluginClass.getSimpleName(), - call.getTargetOwner().getSimpleName(), - call.getName(), - call.getDescription() - ); - events.add(SimpleConditionEvent.violated(call, message)); - } - }); - } - - private boolean isEagerTaskCreation(JavaMethodCall call) { - String methodName = call.getName(); - - if (!EAGER_TASK_CREATION_METHODS.contains(methodName)) { - return false; - } - - JavaClass targetOwner = call.getTargetOwner(); - return targetOwner.isAssignableTo("org.gradle.api.Project") || - targetOwner.isAssignableTo("org.gradle.api.tasks.TaskContainer"); - } - }; - } - - @Override - public Map getRules() { - Map rules = new HashMap<>(); - rules.put("gradle-plugin-lazy-task-registration", pluginsShouldUseLazyTaskRegistration); - return rules; - } } diff --git a/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskActionRule.java b/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskActionRule.java index a13f079..f13c0eb 100644 --- a/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskActionRule.java +++ b/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskActionRule.java @@ -1,6 +1,5 @@ package com.netflix.nebula.archrules.gradleplugins; -import com.netflix.nebula.archrules.core.ArchRulesService; import com.tngtech.archunit.base.DescribedPredicate; import com.tngtech.archunit.core.domain.JavaAccess; import com.tngtech.archunit.core.domain.JavaFieldAccess; @@ -13,14 +12,11 @@ import com.tngtech.archunit.lang.syntax.ArchRuleDefinition; import org.jspecify.annotations.NullMarked; -import java.util.HashMap; -import java.util.Map; - /** * Rules for Gradle task action methods to ensure Gradle 10 compatibility. */ @NullMarked -public class GradleTaskActionRule implements ArchRulesService { +public class GradleTaskActionRule { /** * Prevents {@code @TaskAction} methods from accessing {@code Project}. @@ -112,12 +108,4 @@ private boolean isTargetTypeFieldAccess(JavaAccess access) { } }; } - - @Override - public Map getRules() { - Map rules = new HashMap<>(); - rules.put("gradle-task-action-project-access", taskActionShouldNotAccessProject); - rules.put("gradle-task-action-task-dependencies", taskActionShouldNotCallGetTaskDependencies); - return rules; - } } diff --git a/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskCacheabilityRule.java b/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskCacheabilityRule.java index c8f7c94..c14832b 100644 --- a/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskCacheabilityRule.java +++ b/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskCacheabilityRule.java @@ -1,19 +1,13 @@ package com.netflix.nebula.archrules.gradleplugins; -import com.netflix.nebula.archrules.core.ArchRulesService; -import com.tngtech.archunit.core.domain.JavaClass; -import com.tngtech.archunit.core.domain.JavaField; -import com.tngtech.archunit.core.domain.JavaMethod; -import com.tngtech.archunit.lang.ArchCondition; import com.tngtech.archunit.lang.ArchRule; -import com.tngtech.archunit.lang.ConditionEvents; import com.tngtech.archunit.lang.Priority; -import com.tngtech.archunit.lang.SimpleConditionEvent; import com.tngtech.archunit.lang.syntax.ArchRuleDefinition; import org.jspecify.annotations.NullMarked; -import java.util.HashMap; -import java.util.Map; +import static com.netflix.nebula.archrules.gradleplugins.Predicates.areAnnotatedWithFileInputAnnotation; +import static com.tngtech.archunit.core.domain.properties.CanBeAnnotated.Predicates.annotatedWith; +import static com.tngtech.archunit.lang.conditions.ArchPredicates.are; /** * Rules to ensure cacheable tasks properly declare path sensitivity. @@ -21,12 +15,9 @@ * Cacheable tasks must declare how file paths should be compared for cache key calculation. */ @NullMarked -public class GradleTaskCacheabilityRule implements ArchRulesService { +public class GradleTaskCacheabilityRule { private static final String ANNOTATION_CACHEABLE_TASK = "org.gradle.api.tasks.CacheableTask"; - private static final String ANNOTATION_INPUT_FILE = "org.gradle.api.tasks.InputFile"; - private static final String ANNOTATION_INPUT_FILES = "org.gradle.api.tasks.InputFiles"; - private static final String ANNOTATION_INPUT_DIRECTORY = "org.gradle.api.tasks.InputDirectory"; private static final String ANNOTATION_PATH_SENSITIVE = "org.gradle.api.tasks.PathSensitive"; /** @@ -36,10 +27,11 @@ public class GradleTaskCacheabilityRule implements ArchRulesService { * how file paths affect cache keys. Without this, tasks may not be relocatable * across different machines, breaking the build cache. */ - public static final ArchRule cacheableTasksShouldDeclarePathSensitivity = ArchRuleDefinition.priority(Priority.HIGH) - .classes() - .that().areAnnotatedWith(ANNOTATION_CACHEABLE_TASK) - .should(declarePathSensitivityOnFileInputs()) + public static final ArchRule METHODS_PATH_SENSITIVITY = ArchRuleDefinition.priority(Priority.HIGH) + .methods() + .that(areAnnotatedWithFileInputAnnotation) + .and().areDeclaredInClassesThat(are(annotatedWith(ANNOTATION_CACHEABLE_TASK))) + .should().beAnnotatedWith(ANNOTATION_PATH_SENSITIVE) .allowEmptyShould(true) .because( "Cacheable tasks with file inputs must declare @PathSensitive to specify how paths " + @@ -47,69 +39,22 @@ public class GradleTaskCacheabilityRule implements ArchRulesService { "See https://docs.gradle.org/current/userguide/build_cache.html#sec:task_output_caching_inputs" ); - private static ArchCondition declarePathSensitivityOnFileInputs() { - return new ArchCondition("declare @PathSensitive on file inputs") { - @Override - public void check(JavaClass taskClass, ConditionEvents events) { - for (JavaField field : taskClass.getAllFields()) { - checkFieldPathSensitivity(taskClass, field, events); - } - - for (JavaMethod method : taskClass.getAllMethods()) { - checkMethodPathSensitivity(taskClass, method, events); - } - } - - private void checkFieldPathSensitivity(JavaClass taskClass, JavaField field, ConditionEvents events) { - if (!hasFileInputAnnotation(field)) { - return; - } - - if (!field.isAnnotatedWith(ANNOTATION_PATH_SENSITIVE)) { - String message = String.format( - "Cacheable task %s has field '%s' with file input annotation but missing @PathSensitive. " + - "Add @PathSensitive to specify how file paths affect cache keys.", - taskClass.getSimpleName(), - field.getName() - ); - events.add(SimpleConditionEvent.violated(field, message)); - } - } - - private void checkMethodPathSensitivity(JavaClass taskClass, JavaMethod method, ConditionEvents events) { - if (!hasFileInputAnnotation(method)) { - return; - } - - if (!method.isAnnotatedWith(ANNOTATION_PATH_SENSITIVE)) { - String message = String.format( - "Cacheable task %s has method '%s()' with file input annotation but missing @PathSensitive. " + - "Add @PathSensitive to specify how file paths affect cache keys.", - taskClass.getSimpleName(), - method.getName() - ); - events.add(SimpleConditionEvent.violated(method, message)); - } - } - - private boolean hasFileInputAnnotation(JavaField field) { - return field.isAnnotatedWith(ANNOTATION_INPUT_FILE) || - field.isAnnotatedWith(ANNOTATION_INPUT_FILES) || - field.isAnnotatedWith(ANNOTATION_INPUT_DIRECTORY); - } - - private boolean hasFileInputAnnotation(JavaMethod method) { - return method.isAnnotatedWith(ANNOTATION_INPUT_FILE) || - method.isAnnotatedWith(ANNOTATION_INPUT_FILES) || - method.isAnnotatedWith(ANNOTATION_INPUT_DIRECTORY); - } - }; - } - - @Override - public Map getRules() { - Map rules = new HashMap<>(); - rules.put("gradle-task-cacheable-path-sensitivity", cacheableTasksShouldDeclarePathSensitivity); - return rules; - } + /** + * Ensures that cacheable tasks declare path sensitivity on file inputs. + *

+ * Cacheable tasks with file inputs must specify {@code @PathSensitive} to define + * how file paths affect cache keys. Without this, tasks may not be relocatable + * across different machines, breaking the build cache. + */ + public static final ArchRule FIELDS_PATH_SENSITIVITY = ArchRuleDefinition.priority(Priority.HIGH) + .fields() + .that(areAnnotatedWithFileInputAnnotation) + .and().areDeclaredInClassesThat(are(annotatedWith(ANNOTATION_CACHEABLE_TASK))) + .should().beAnnotatedWith(ANNOTATION_PATH_SENSITIVE) + .allowEmptyShould(true) + .because( + "Cacheable tasks with file inputs must declare @PathSensitive to specify how paths " + + "affect cache keys. This ensures build cache entries are relocatable across machines. " + + "See https://docs.gradle.org/current/userguide/build_cache.html#sec:task_output_caching_inputs" + ); } diff --git a/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskInputOutputRule.java b/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskInputOutputRule.java index b8ea093..ea7fb0e 100644 --- a/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskInputOutputRule.java +++ b/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskInputOutputRule.java @@ -1,14 +1,11 @@ package com.netflix.nebula.archrules.gradleplugins; import com.netflix.nebula.archrules.core.ArchRulesService; -import com.tngtech.archunit.core.domain.JavaClass; -import com.tngtech.archunit.core.domain.JavaField; -import com.tngtech.archunit.core.domain.JavaMethod; +import com.tngtech.archunit.base.DescribedPredicate; +import com.tngtech.archunit.core.domain.properties.CanBeAnnotated; import com.tngtech.archunit.lang.ArchCondition; import com.tngtech.archunit.lang.ArchRule; -import com.tngtech.archunit.lang.ConditionEvents; import com.tngtech.archunit.lang.Priority; -import com.tngtech.archunit.lang.SimpleConditionEvent; import com.tngtech.archunit.lang.syntax.ArchRuleDefinition; import org.jspecify.annotations.NullMarked; @@ -18,13 +15,20 @@ import java.util.Map; import java.util.Set; +import static com.netflix.nebula.archrules.gradleplugins.Predicates.annotatedWithAny; +import static com.netflix.nebula.archrules.gradleplugins.Predicates.containAnyFieldsInClassHierarchyThat; +import static com.netflix.nebula.archrules.gradleplugins.Predicates.containAnyMethodsInClassHierarchyThat; +import static com.netflix.nebula.archrules.gradleplugins.Predicates.haveTaskAction; +import static com.tngtech.archunit.lang.ArchCondition.from; +import static com.tngtech.archunit.lang.conditions.ArchPredicates.are; + /** * Rules to ensure Gradle tasks properly declare their inputs and outputs. *

* Tasks must declare inputs and outputs for incremental builds and caching to work correctly. */ @NullMarked -public class GradleTaskInputOutputRule implements ArchRulesService { +public class GradleTaskInputOutputRule { private static final String ANNOTATION_INPUT = "org.gradle.api.tasks.Input"; private static final String ANNOTATION_INPUT_FILE = "org.gradle.api.tasks.InputFile"; @@ -34,9 +38,6 @@ public class GradleTaskInputOutputRule implements ArchRulesService { private static final String ANNOTATION_OUTPUT_FILES = "org.gradle.api.tasks.OutputFiles"; private static final String ANNOTATION_OUTPUT_DIRECTORY = "org.gradle.api.tasks.OutputDirectory"; private static final String ANNOTATION_OUTPUT_DIRECTORIES = "org.gradle.api.tasks.OutputDirectories"; - private static final String ANNOTATION_TASK_ACTION = "org.gradle.api.tasks.TaskAction"; - - private static class LazyHolder { private static final Set INPUT_OUTPUT_ANNOTATIONS = new HashSet<>(Arrays.asList( ANNOTATION_INPUT, ANNOTATION_INPUT_FILE, @@ -47,11 +48,10 @@ private static class LazyHolder { ANNOTATION_OUTPUT_DIRECTORY, ANNOTATION_OUTPUT_DIRECTORIES )); - } - private static Set getInputOutputAnnotations() { - return LazyHolder.INPUT_OUTPUT_ANNOTATIONS; - } + private static final DescribedPredicate annotatedWithInputOutputAnnotations = + annotatedWithAny(INPUT_OUTPUT_ANNOTATIONS) + .as("annotated with Input and/or Output annotations"); /** * Ensures that task classes declare at least one input or output. @@ -59,12 +59,14 @@ private static Set getInputOutputAnnotations() { * Tasks without declared inputs/outputs cannot participate in incremental builds * or build caching, which significantly impacts build performance. */ - public static final ArchRule tasksShouldDeclareInputsOrOutputs = ArchRuleDefinition.priority(Priority.HIGH) + public static final ArchRule INPUTS_OUTPUTS = ArchRuleDefinition.priority(Priority.HIGH) .classes() .that().areAssignableTo("org.gradle.api.DefaultTask") .and().areNotInterfaces() + .and(haveTaskAction) .and().doNotHaveSimpleName("DefaultTask") - .should(declareInputsOrOutputs()) + .should(from(containAnyMethodsInClassHierarchyThat(are(annotatedWithInputOutputAnnotations)))) + .orShould(from(containAnyFieldsInClassHierarchyThat(are(annotatedWithInputOutputAnnotations)))) .allowEmptyShould(true) .because( "Tasks must declare inputs and outputs using @Input, @InputFile, @InputDirectory, " + @@ -72,65 +74,4 @@ private static Set getInputOutputAnnotations() { "This is required for incremental builds and caching to work correctly. " + "See https://docs.gradle.org/current/userguide/incremental_build.html" ); - - private static ArchCondition declareInputsOrOutputs() { - return new ArchCondition("declare at least one input or output") { - @Override - public void check(JavaClass taskClass, ConditionEvents events) { - if (!hasTaskAction(taskClass)) { - return; - } - - boolean hasInputOrOutput = hasInputOutputAnnotation(taskClass); - - if (!hasInputOrOutput) { - String message = String.format( - "Task %s has @TaskAction method(s) but no declared inputs or outputs. " + - "Add @Input, @InputFile, @InputDirectory, @Output, @OutputFile, or @OutputDirectory " + - "annotations to enable incremental builds and caching.", - taskClass.getSimpleName() - ); - events.add(SimpleConditionEvent.violated(taskClass, message)); - } - } - - private boolean hasTaskAction(JavaClass taskClass) { - return taskClass.getAllMethods().stream() - .anyMatch(method -> method.isAnnotatedWith(ANNOTATION_TASK_ACTION)); - } - - private boolean hasInputOutputAnnotation(JavaClass taskClass) { - for (JavaField field : taskClass.getAllFields()) { - if (hasAnyInputOutputAnnotation(field)) { - return true; - } - } - - for (JavaMethod method : taskClass.getAllMethods()) { - if (hasAnyInputOutputAnnotation(method)) { - return true; - } - } - - return false; - } - - private boolean hasAnyInputOutputAnnotation(JavaField field) { - return getInputOutputAnnotations().stream() - .anyMatch(field::isAnnotatedWith); - } - - private boolean hasAnyInputOutputAnnotation(JavaMethod method) { - return getInputOutputAnnotations().stream() - .anyMatch(method::isAnnotatedWith); - } - }; - } - - @Override - public Map getRules() { - Map rules = new HashMap<>(); - rules.put("gradle-task-input-output-declaration", tasksShouldDeclareInputsOrOutputs); - return rules; - } } diff --git a/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskProviderApiRule.java b/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskProviderApiRule.java index e2d10ab..4a0daaf 100644 --- a/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskProviderApiRule.java +++ b/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskProviderApiRule.java @@ -1,14 +1,16 @@ package com.netflix.nebula.archrules.gradleplugins; -import com.netflix.nebula.archrules.core.ArchRulesService; +import com.tngtech.archunit.base.DescribedPredicate; import com.tngtech.archunit.core.domain.JavaClass; import com.tngtech.archunit.core.domain.JavaField; import com.tngtech.archunit.core.domain.JavaMethod; +import com.tngtech.archunit.core.domain.JavaModifier; import com.tngtech.archunit.lang.ArchCondition; import com.tngtech.archunit.lang.ArchRule; import com.tngtech.archunit.lang.ConditionEvents; import com.tngtech.archunit.lang.Priority; import com.tngtech.archunit.lang.SimpleConditionEvent; +import com.tngtech.archunit.lang.conditions.ArchPredicates; import com.tngtech.archunit.lang.syntax.ArchRuleDefinition; import org.jspecify.annotations.NullMarked; @@ -18,6 +20,15 @@ import java.util.Map; import java.util.Set; +import static com.netflix.nebula.archrules.gradleplugins.Predicates.getters; +import static com.netflix.nebula.archrules.gradleplugins.Predicates.hasRichPropertyReturnType; +import static com.tngtech.archunit.base.DescribedPredicate.not; +import static com.tngtech.archunit.core.domain.JavaMember.Predicates.declaredIn; +import static com.tngtech.archunit.core.domain.JavaModifier.PRIVATE; +import static com.tngtech.archunit.core.domain.properties.CanBeAnnotated.Predicates.annotatedWith; +import static com.tngtech.archunit.core.domain.properties.HasModifiers.Predicates.modifier; +import static com.tngtech.archunit.lang.conditions.ArchPredicates.are; + /** * Rules for Gradle task classes to ensure they use the Provider API for lazy configuration. *

@@ -25,7 +36,7 @@ * enables lazy configuration and configuration avoidance, which are critical for build performance. */ @NullMarked -public class GradleTaskProviderApiRule implements ArchRulesService { +class GradleTaskProviderApiRule { private static final String JAVA_IO_FILE = "java.io.File"; private static final String JAVA_LANG_STRING = "java.lang.String"; @@ -68,6 +79,7 @@ private static class LazyHolder { )); private static final Map TYPE_TO_PROVIDER; + static { Map map = new HashMap<>(); map.put(JAVA_UTIL_LIST, RECOMMENDATION_LIST_PROPERTY); @@ -93,7 +105,7 @@ private static Map getTypeToProviderMap() { * ({@code Property}, {@code RegularFileProperty}, {@code DirectoryProperty}, etc.) * instead of plain types for lazy configuration. */ - public static final ArchRule taskInputOutputPropertiesShouldUseProviderApi = ArchRuleDefinition.priority(Priority.MEDIUM) + static final ArchRule PROVIDER_PROPERTIES = ArchRuleDefinition.priority(Priority.MEDIUM) .classes() .that().areAssignableTo("org.gradle.api.Task") .and().areNotInterfaces() @@ -237,10 +249,23 @@ private String getRecommendationForType(JavaClass type, boolean isFileAnnotation }; } - @Override - public Map getRules() { - Map rules = new HashMap<>(); - rules.put("gradle-task-provider-api", taskInputOutputPropertiesShouldUseProviderApi); - return rules; - } + static final DescribedPredicate richTaskPropertyGetters = ArchPredicates.are(getters) + .and(are(hasRichPropertyReturnType)) + .and(not(modifier(PRIVATE))) + .and(not(annotatedWith("javax.inject.Inject"))) + .and(not(annotatedWith("org.gradle.api.tasks.options.OptionValues"))) + .and(not(declaredIn("org.gradle.api.Task"))) + .and(not(declaredIn("org.gradle.api.DefaultTask"))) + .and(not(declaredIn("org.gradle.api.internal.AbstractTask"))) + .as("task property getters"); + + /** + * Inspired by + * {@link Gradle} + */ + static final ArchRule ABSTRACT_GETTERS = ArchRuleDefinition.priority(Priority.MEDIUM) + .methods().that(are(richTaskPropertyGetters)) + .should().haveModifier(JavaModifier.ABSTRACT) + .allowEmptyShould(true) + .because("task implementations should define properties as abstract getters"); } diff --git a/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/Predicates.java b/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/Predicates.java new file mode 100644 index 0000000..8625a86 --- /dev/null +++ b/archrules-gradle-plugin-development/src/archRules/java/com/netflix/nebula/archrules/gradleplugins/Predicates.java @@ -0,0 +1,119 @@ +package com.netflix.nebula.archrules.gradleplugins; + +import com.tngtech.archunit.base.ChainableFunction; +import com.tngtech.archunit.base.DescribedPredicate; +import com.tngtech.archunit.core.domain.JavaAccess; +import com.tngtech.archunit.core.domain.JavaClass; +import com.tngtech.archunit.core.domain.JavaField; +import com.tngtech.archunit.core.domain.JavaMethod; +import com.tngtech.archunit.core.domain.JavaModifier; +import com.tngtech.archunit.core.domain.properties.CanBeAnnotated; +import com.tngtech.archunit.core.domain.properties.HasReturnType; +import com.tngtech.archunit.lang.conditions.ArchPredicates; + +import java.util.Set; + +import static com.tngtech.archunit.core.domain.JavaAccess.Predicates.target; +import static com.tngtech.archunit.core.domain.JavaAccess.Predicates.targetOwner; +import static com.tngtech.archunit.core.domain.JavaClass.Predicates.assignableTo; +import static com.tngtech.archunit.core.domain.JavaClass.Predicates.containAnyMethodsThat; +import static com.tngtech.archunit.core.domain.JavaClass.Predicates.resideInAPackage; +import static com.tngtech.archunit.core.domain.properties.CanBeAnnotated.Predicates.annotatedWith; +import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.name; +import static com.tngtech.archunit.core.domain.properties.HasReturnType.Predicates.rawReturnType; +import static com.tngtech.archunit.core.domain.properties.HasType.Predicates.rawType; +import static com.tngtech.archunit.lang.conditions.ArchPredicates.are; +import static com.tngtech.archunit.lang.conditions.ArchPredicates.has; + +class Predicates { + static final DescribedPredicate getters = new DescribedPredicate("getters") { + @Override + public boolean test(JavaMethod input) { + if (input.getModifiers().contains(JavaModifier.STATIC)) { + return false; + } + if (!input.getParameters().isEmpty()) { + return false; + } + if (input.getName().startsWith("get")) { + if (Character.isLowerCase(input.getName().charAt(3))) { + return false; + } + return true; + } + if (input.getName().startsWith("is")) { + if (input.getRawReturnType().isAssignableTo(Boolean.class)) { + return false; + } + if (Character.isLowerCase(input.getName().charAt(2))) { + return false; + } + return true; + } + return false; + } + }; + + static final DescribedPredicate hasRichPropertyReturnType = ArchPredicates + .has(rawReturnType(assignableTo("org.gradle.api.provider.Provider") + .or(assignableTo("org.gradle.api.file.FileCollection")))) + .as("has rich property return type"); + + static final DescribedPredicate> taskIsCreatedEagerly = ArchPredicates + .is(target(has(name("task").or(name("create"))))) + .and(targetOwner(assignableTo("org.gradle.api.Project")) + .or(targetOwner(assignableTo("org.gradle.api.tasks.TaskContainer")))) + .as("task is created eagerly"); + + static final DescribedPredicate gradleClass = ArchPredicates.is(resideInAPackage("org.gradle..")); + static final DescribedPredicate deprecatedGradleClass = ArchPredicates.is(gradleClass).and(annotatedWith(Deprecated.class)); + static final DescribedPredicate internalGradleClass = ArchPredicates.is(gradleClass).and(resideInAPackage("..internal..")); + + static final DescribedPredicate> accessDeprecatedGradleApi = ArchPredicates + .is(targetOwner(deprecatedGradleClass)) + .or(target(annotatedWith(Deprecated.class))); + + static final DescribedPredicate haveTaskAction = + ArchPredicates.have(containAnyMethodsThat(are(annotatedWith("org.gradle.api.tasks.TaskAction")))); + + static DescribedPredicate annotatedWithAny(Set annotationClasses) { + return annotationClasses.stream() + .map(CanBeAnnotated.Predicates::annotatedWith) + .reduce((a, b) -> a.or(b)) + .orElseGet(() -> annotatedWith(rawType(assignableTo(Object.class)))) + .as("annotated with any [%s]", String.join(", ", annotationClasses)); + } + + static DescribedPredicate containAnyMethodsInClassHierarchyThat(DescribedPredicate predicate) { + return new ContainAnyMembersInClassHierarchyThatPredicate<>("methods", GET_ALL_METHODS, predicate); + } + + static DescribedPredicate containAnyFieldsInClassHierarchyThat(DescribedPredicate predicate) { + return new ContainAnyMembersInClassHierarchyThatPredicate<>("fields", GET_ALL_FIELDS, predicate); + } + + static final ChainableFunction> GET_ALL_METHODS = + new ChainableFunction>() { + @Override + public Set apply(JavaClass input) { + return input.getAllMethods(); + } + }; + + static final ChainableFunction> GET_ALL_FIELDS = + new ChainableFunction>() { + @Override + public Set apply(JavaClass input) { + return input.getAllFields(); + } + }; + + private static final String ANNOTATION_INPUT_FILE = "org.gradle.api.tasks.InputFile"; + private static final String ANNOTATION_INPUT_FILES = "org.gradle.api.tasks.InputFiles"; + private static final String ANNOTATION_INPUT_DIRECTORY = "org.gradle.api.tasks.InputDirectory"; + static final DescribedPredicate areAnnotatedWithFileInputAnnotation = + ArchPredicates.are(annotatedWith(ANNOTATION_INPUT_FILE)) + .or(annotatedWith(ANNOTATION_INPUT_FILES)) + .or(annotatedWith(ANNOTATION_INPUT_DIRECTORY)) + .as("annotated with Input file annotations"); +} diff --git a/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradleDeprecatedApiRuleTest.java b/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradleDeprecatedApiRuleTest.java index bb09ada..ba314c8 100644 --- a/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradleDeprecatedApiRuleTest.java +++ b/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradleDeprecatedApiRuleTest.java @@ -2,18 +2,25 @@ import com.netflix.nebula.archrules.core.Runner; import com.tngtech.archunit.lang.EvaluationResult; +import org.gradle.FakeDeprecatedGradleClass; +import org.gradle.FakeDeprecatedGradleMethod; import org.gradle.api.DefaultTask; import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.tasks.TaskAction; import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import static org.assertj.core.api.Assertions.assertThat; public class GradleDeprecatedApiRuleTest { - private static final Logger LOG = LoggerFactory.getLogger(GradleDeprecatedApiRuleTest.class); + @Test + public void pluginNotUsingDeprecatedApis_should_fail() { + final EvaluationResult result = Runner.check( + GradleDeprecatedApiRule.pluginsShouldNotUseDeprecatedGradleApis, + PluginUsingDeprecatedApis.class + ); + assertThat(result.hasViolation()).isTrue(); + } @Test public void pluginNotUsingDeprecatedApis_should_pass() { @@ -21,21 +28,27 @@ public void pluginNotUsingDeprecatedApis_should_pass() { GradleDeprecatedApiRule.pluginsShouldNotUseDeprecatedGradleApis, PluginNotUsingDeprecatedApis.class ); - LOG.info(result.getFailureReport().toString()); assertThat(result.hasViolation()).isFalse(); } + @Test + public void taskUsingDeprecatedApis_should_fail() { + final EvaluationResult result = Runner.check( + GradleDeprecatedApiRule.tasksShouldNotUseDeprecatedGradleApis, + TaskUsingDeprecatedClass.class + ); + assertThat(result.hasViolation()).isTrue(); + } + @Test public void taskNotUsingDeprecatedApis_should_pass() { final EvaluationResult result = Runner.check( GradleDeprecatedApiRule.tasksShouldNotUseDeprecatedGradleApis, TaskNotUsingDeprecatedApis.class ); - LOG.info(result.getFailureReport().toString()); assertThat(result.hasViolation()).isFalse(); } - @SuppressWarnings("unused") public static class PluginNotUsingDeprecatedApis implements Plugin { @Override public void apply(Project project) { @@ -46,6 +59,13 @@ public void apply(Project project) { } } + public static class PluginUsingDeprecatedApis implements Plugin { + @Override + public void apply(Project project) { + FakeDeprecatedGradleMethod.aMethod(); + } + } + @SuppressWarnings("unused") public static abstract class TaskNotUsingDeprecatedApis extends DefaultTask { @TaskAction @@ -53,4 +73,11 @@ public void execute() { System.out.println("Task executed without deprecated APIs"); } } + + public static abstract class TaskUsingDeprecatedClass extends FakeDeprecatedGradleClass { + @TaskAction + public void execute() { + System.out.println("Task executed without deprecated APIs"); + } + } } diff --git a/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradleInternalApiRuleTest.java b/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradleInternalApiRuleTest.java index 383f4a2..ba2420e 100644 --- a/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradleInternalApiRuleTest.java +++ b/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradleInternalApiRuleTest.java @@ -21,7 +21,7 @@ public class GradleInternalApiRuleTest { @Test public void pluginNotUsingInternalApis_should_pass() { final EvaluationResult result = Runner.check( - GradleInternalApiRule.pluginsShouldNotUseInternalGradleApis, + GradleInternalApiRule.PLUGIN_INTERNAL, PluginNotUsingInternalApis.class ); LOG.info(result.getFailureReport().toString()); @@ -31,7 +31,7 @@ public void pluginNotUsingInternalApis_should_pass() { @Test public void taskNotUsingInternalApis_should_pass() { final EvaluationResult result = Runner.check( - GradleInternalApiRule.tasksShouldNotUseInternalGradleApis, + GradleInternalApiRule.TASK_INTERNAL, TaskNotUsingInternalApis.class ); LOG.info(result.getFailureReport().toString()); @@ -41,7 +41,7 @@ public void taskNotUsingInternalApis_should_pass() { @Test public void pluginUsingPublicGradleApis_should_pass() { final EvaluationResult result = Runner.check( - GradleInternalApiRule.pluginsShouldNotUseInternalGradleApis, + GradleInternalApiRule.PLUGIN_INTERNAL, PluginUsingPublicGradleApis.class ); LOG.info(result.getFailureReport().toString()); @@ -51,7 +51,7 @@ public void pluginUsingPublicGradleApis_should_pass() { @Test public void pluginUsingInternalApi_should_fail() { final EvaluationResult result = Runner.check( - GradleInternalApiRule.pluginsShouldNotUseInternalGradleApis, + GradleInternalApiRule.PLUGIN_INTERNAL, PluginUsingInternalApi.class ); LOG.info(result.getFailureReport().toString()); @@ -63,7 +63,7 @@ public void pluginUsingInternalApi_should_fail() { @Test public void taskUsingInternalApi_should_fail() { final EvaluationResult result = Runner.check( - GradleInternalApiRule.tasksShouldNotUseInternalGradleApis, + GradleInternalApiRule.TASK_INTERNAL, TaskUsingInternalApi.class ); LOG.info(result.getFailureReport().toString()); diff --git a/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradlePluginLazyTaskRegistrationRuleTest.java b/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradlePluginLazyTaskRegistrationRuleTest.java index b0ebcb1..021c4b8 100644 --- a/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradlePluginLazyTaskRegistrationRuleTest.java +++ b/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradlePluginLazyTaskRegistrationRuleTest.java @@ -5,7 +5,6 @@ import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.Task; -import org.gradle.api.tasks.TaskProvider; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,30 +17,33 @@ public class GradlePluginLazyTaskRegistrationRuleTest { @Test public void pluginUsingEagerTaskCreation_should_fail() { final EvaluationResult result = Runner.check( - GradlePluginLazyTaskRegistrationRule.pluginsShouldUseLazyTaskRegistration, + GradlePluginLazyTaskRegistrationRule.LAZY_TASK_CREATION, PluginUsingEagerTaskCreation.class ); LOG.info(result.getFailureReport().toString()); assertThat(result.hasViolation()).isTrue(); - assertThat(result.getFailureReport().toString()).contains("uses eager task creation"); - assertThat(result.getFailureReport().toString()).contains("Use tasks.register()"); + assertThat(result.getFailureReport().toString()).contains("where task is created eagerly"); + assertThat(result.getFailureReport().toString()).contains("use tasks.register()"); + assertThat(result.getFailureReport().toString()) + .as("wrong call is shown") + .contains("calls method "); } @Test public void pluginUsingTasksCreate_should_fail() { final EvaluationResult result = Runner.check( - GradlePluginLazyTaskRegistrationRule.pluginsShouldUseLazyTaskRegistration, + GradlePluginLazyTaskRegistrationRule.LAZY_TASK_CREATION, PluginUsingTasksCreate.class ); LOG.info(result.getFailureReport().toString()); assertThat(result.hasViolation()).isTrue(); - assertThat(result.getFailureReport().toString()).contains("uses eager task creation"); + assertThat(result.getFailureReport().toString()).contains("where task is created eagerly"); } @Test public void pluginUsingLazyTaskRegistration_should_pass() { final EvaluationResult result = Runner.check( - GradlePluginLazyTaskRegistrationRule.pluginsShouldUseLazyTaskRegistration, + GradlePluginLazyTaskRegistrationRule.LAZY_TASK_CREATION, PluginUsingLazyTaskRegistration.class ); LOG.info(result.getFailureReport().toString()); @@ -51,7 +53,7 @@ public void pluginUsingLazyTaskRegistration_should_pass() { @Test public void pluginUsingTasksNamed_should_pass() { final EvaluationResult result = Runner.check( - GradlePluginLazyTaskRegistrationRule.pluginsShouldUseLazyTaskRegistration, + GradlePluginLazyTaskRegistrationRule.LAZY_TASK_CREATION, PluginUsingTasksNamed.class ); LOG.info(result.getFailureReport().toString()); diff --git a/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskCacheabilityRuleTest.java b/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskCacheabilityRuleTest.java index e19e9ab..4cb5c46 100644 --- a/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskCacheabilityRuleTest.java +++ b/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskCacheabilityRuleTest.java @@ -24,18 +24,17 @@ public class GradleTaskCacheabilityRuleTest { @Test public void cacheableTaskWithoutPathSensitive_should_fail() { final EvaluationResult result = Runner.check( - GradleTaskCacheabilityRule.cacheableTasksShouldDeclarePathSensitivity, + GradleTaskCacheabilityRule.FIELDS_PATH_SENSITIVITY, CacheableTaskWithoutPathSensitive.class ); - LOG.info(result.getFailureReport().toString()); assertThat(result.hasViolation()).isTrue(); - assertThat(result.getFailureReport().toString()).contains("missing @PathSensitive"); + assertThat(result.getFailureReport().toString()).contains("should be annotated with @PathSensitive"); } @Test public void cacheableTaskWithPathSensitive_should_pass() { final EvaluationResult result = Runner.check( - GradleTaskCacheabilityRule.cacheableTasksShouldDeclarePathSensitivity, + GradleTaskCacheabilityRule.FIELDS_PATH_SENSITIVITY, CacheableTaskWithPathSensitive.class ); LOG.info(result.getFailureReport().toString()); @@ -45,18 +44,18 @@ public void cacheableTaskWithPathSensitive_should_pass() { @Test public void cacheableTaskWithInputFileMethodMissingPathSensitive_should_fail() { final EvaluationResult result = Runner.check( - GradleTaskCacheabilityRule.cacheableTasksShouldDeclarePathSensitivity, + GradleTaskCacheabilityRule.METHODS_PATH_SENSITIVITY, CacheableTaskWithInputFileMethodMissingPathSensitive.class ); LOG.info(result.getFailureReport().toString()); assertThat(result.hasViolation()).isTrue(); - assertThat(result.getFailureReport().toString()).contains("missing @PathSensitive"); + assertThat(result.getFailureReport().toString()).contains("should be annotated with @PathSensitive"); } @Test public void cacheableTaskWithInputFileMethodWithPathSensitive_should_pass() { final EvaluationResult result = Runner.check( - GradleTaskCacheabilityRule.cacheableTasksShouldDeclarePathSensitivity, + GradleTaskCacheabilityRule.FIELDS_PATH_SENSITIVITY, CacheableTaskWithInputFileMethodWithPathSensitive.class ); LOG.info(result.getFailureReport().toString()); @@ -66,7 +65,7 @@ public void cacheableTaskWithInputFileMethodWithPathSensitive_should_pass() { @Test public void cacheableTaskWithOnlyOutputs_should_pass() { final EvaluationResult result = Runner.check( - GradleTaskCacheabilityRule.cacheableTasksShouldDeclarePathSensitivity, + GradleTaskCacheabilityRule.FIELDS_PATH_SENSITIVITY, CacheableTaskWithOnlyOutputs.class ); LOG.info(result.getFailureReport().toString()); @@ -76,7 +75,7 @@ public void cacheableTaskWithOnlyOutputs_should_pass() { @Test public void nonCacheableTaskWithoutPathSensitive_should_pass() { final EvaluationResult result = Runner.check( - GradleTaskCacheabilityRule.cacheableTasksShouldDeclarePathSensitivity, + GradleTaskCacheabilityRule.FIELDS_PATH_SENSITIVITY, NonCacheableTaskWithoutPathSensitive.class ); LOG.info(result.getFailureReport().toString()); diff --git a/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskInputOutputRuleTest.java b/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskInputOutputRuleTest.java index fd7125f..b77c375 100644 --- a/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskInputOutputRuleTest.java +++ b/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskInputOutputRuleTest.java @@ -21,18 +21,19 @@ public class GradleTaskInputOutputRuleTest { @Test public void taskWithoutInputOutput_should_fail() { final EvaluationResult result = Runner.check( - GradleTaskInputOutputRule.tasksShouldDeclareInputsOrOutputs, + GradleTaskInputOutputRule.INPUTS_OUTPUTS, TaskWithoutInputOutput.class ); - LOG.info(result.getFailureReport().toString()); assertThat(result.hasViolation()).isTrue(); - assertThat(result.getFailureReport().toString()).contains("no declared inputs or outputs"); + assertThat(result.getFailureReport().toString()) + .contains("should contain any methods that are annotated with Input and/or Output annotations") + .contains("should contain any fields that are annotated with Input and/or Output annotations"); } @Test public void taskWithInputAnnotation_should_pass() { final EvaluationResult result = Runner.check( - GradleTaskInputOutputRule.tasksShouldDeclareInputsOrOutputs, + GradleTaskInputOutputRule.INPUTS_OUTPUTS, TaskWithInputAnnotation.class ); LOG.info(result.getFailureReport().toString()); @@ -42,7 +43,7 @@ public void taskWithInputAnnotation_should_pass() { @Test public void taskWithInputFileAnnotation_should_pass() { final EvaluationResult result = Runner.check( - GradleTaskInputOutputRule.tasksShouldDeclareInputsOrOutputs, + GradleTaskInputOutputRule.INPUTS_OUTPUTS, TaskWithInputFileAnnotation.class ); LOG.info(result.getFailureReport().toString()); @@ -52,7 +53,7 @@ public void taskWithInputFileAnnotation_should_pass() { @Test public void taskWithOutputAnnotation_should_pass() { final EvaluationResult result = Runner.check( - GradleTaskInputOutputRule.tasksShouldDeclareInputsOrOutputs, + GradleTaskInputOutputRule.INPUTS_OUTPUTS, TaskWithOutputAnnotation.class ); LOG.info(result.getFailureReport().toString()); @@ -62,7 +63,7 @@ public void taskWithOutputAnnotation_should_pass() { @Test public void taskWithoutTaskAction_should_pass() { final EvaluationResult result = Runner.check( - GradleTaskInputOutputRule.tasksShouldDeclareInputsOrOutputs, + GradleTaskInputOutputRule.INPUTS_OUTPUTS, TaskWithoutTaskAction.class ); LOG.info(result.getFailureReport().toString()); diff --git a/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskProviderApiRuleTest.java b/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskProviderApiRuleTest.java index e533a57..8cb0664 100644 --- a/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskProviderApiRuleTest.java +++ b/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/GradleTaskProviderApiRuleTest.java @@ -1,16 +1,18 @@ package com.netflix.nebula.archrules.gradleplugins; import com.netflix.nebula.archrules.core.Runner; +import com.tngtech.archunit.core.importer.ClassFileImporter; import com.tngtech.archunit.lang.EvaluationResult; import org.gradle.api.DefaultTask; -import org.gradle.api.provider.Property; -import org.gradle.api.file.RegularFileProperty; import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.internal.provider.DefaultProvider; +import org.gradle.api.provider.Property; +import org.gradle.api.provider.Provider; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.InputFile; -import org.gradle.api.tasks.InputDirectory; -import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.OutputDirectory; +import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.TaskAction; import org.junit.jupiter.api.Test; import org.slf4j.Logger; @@ -18,6 +20,7 @@ import java.io.File; +import static com.netflix.nebula.archrules.gradleplugins.GradleTaskProviderApiRule.richTaskPropertyGetters; import static org.assertj.core.api.Assertions.assertThat; public class GradleTaskProviderApiRuleTest { @@ -26,7 +29,7 @@ public class GradleTaskProviderApiRuleTest { @Test public void taskWithPlainStringInput_should_fail() { final EvaluationResult result = Runner.check( - GradleTaskProviderApiRule.taskInputOutputPropertiesShouldUseProviderApi, + GradleTaskProviderApiRule.PROVIDER_PROPERTIES, TaskWithPlainStringInput.class ); LOG.info(result.getFailureReport().toString()); @@ -37,7 +40,7 @@ public void taskWithPlainStringInput_should_fail() { @Test public void taskWithPlainFileInputField_should_fail() { final EvaluationResult result = Runner.check( - GradleTaskProviderApiRule.taskInputOutputPropertiesShouldUseProviderApi, + GradleTaskProviderApiRule.PROVIDER_PROPERTIES, TaskWithPlainFileInputField.class ); LOG.info(result.getFailureReport().toString()); @@ -48,7 +51,7 @@ public void taskWithPlainFileInputField_should_fail() { @Test public void taskWithPlainFileOutputGetter_should_fail() { final EvaluationResult result = Runner.check( - GradleTaskProviderApiRule.taskInputOutputPropertiesShouldUseProviderApi, + GradleTaskProviderApiRule.PROVIDER_PROPERTIES, TaskWithPlainFileOutputGetter.class ); LOG.info(result.getFailureReport().toString()); @@ -59,7 +62,7 @@ public void taskWithPlainFileOutputGetter_should_fail() { @Test public void taskWithPropertyApiInput_should_pass() { final EvaluationResult result = Runner.check( - GradleTaskProviderApiRule.taskInputOutputPropertiesShouldUseProviderApi, + GradleTaskProviderApiRule.PROVIDER_PROPERTIES, TaskWithPropertyApiInput.class ); LOG.info(result.getFailureReport().toString()); @@ -69,7 +72,7 @@ public void taskWithPropertyApiInput_should_pass() { @Test public void taskWithRegularFileProperty_should_pass() { final EvaluationResult result = Runner.check( - GradleTaskProviderApiRule.taskInputOutputPropertiesShouldUseProviderApi, + GradleTaskProviderApiRule.PROVIDER_PROPERTIES, TaskWithRegularFileProperty.class ); LOG.info(result.getFailureReport().toString()); @@ -79,7 +82,7 @@ public void taskWithRegularFileProperty_should_pass() { @Test public void taskWithDirectoryProperty_should_pass() { final EvaluationResult result = Runner.check( - GradleTaskProviderApiRule.taskInputOutputPropertiesShouldUseProviderApi, + GradleTaskProviderApiRule.PROVIDER_PROPERTIES, TaskWithDirectoryProperty.class ); LOG.info(result.getFailureReport().toString()); @@ -89,14 +92,65 @@ public void taskWithDirectoryProperty_should_pass() { @Test public void taskWithoutAnnotations_should_pass() { final EvaluationResult result = Runner.check( - GradleTaskProviderApiRule.taskInputOutputPropertiesShouldUseProviderApi, + GradleTaskProviderApiRule.PROVIDER_PROPERTIES, TaskWithoutAnnotations.class ); LOG.info(result.getFailureReport().toString()); assertThat(result.hasViolation()).isFalse(); } - @SuppressWarnings("unused") + @Test + public void test_richTaskPropertyGetters() { + boolean result = richTaskPropertyGetters + .test(new ClassFileImporter().importClass(TaskWithAbstractGetter.class).getMethod("getMessage")); + assertThat(result).isTrue(); + } + + @Test + public void test_abstractGetters_fail() { + final EvaluationResult result = Runner.check( + GradleTaskProviderApiRule.ABSTRACT_GETTERS, + TaskWithConcreteGetter.class + ); + assertThat(result.hasViolation()).isTrue(); + } + + @Test + public void test_abstractGetters_pass() { + final EvaluationResult result = Runner.check( + GradleTaskProviderApiRule.ABSTRACT_GETTERS, + TaskWithAbstractGetter.class + ); + assertThat(result.hasViolation()) + .as(result.getFailureReport().toString()) + .isFalse(); + } + + public static abstract class TaskWithAbstractGetter extends DefaultTask { + + @Input + public abstract Provider getMessage(); + + @TaskAction + public void execute() { + System.out.println(" "); + } + } + + public static abstract class TaskWithConcreteGetter extends DefaultTask { + public String message; + + @Input + public Provider getMessage() { + return new DefaultProvider<>(() -> message); + } + + @TaskAction + public void execute() { + System.out.println(message); + } + } + public static abstract class TaskWithPlainStringInput extends DefaultTask { @Input public String message; @@ -107,7 +161,6 @@ public void execute() { } } - @SuppressWarnings("unused") public static abstract class TaskWithPlainFileInputField extends DefaultTask { @InputFile public File inputFile; diff --git a/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/PredicatesTest.java b/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/PredicatesTest.java new file mode 100644 index 0000000..2d72611 --- /dev/null +++ b/archrules-gradle-plugin-development/src/archRulesTest/java/com/netflix/nebula/archrules/gradleplugins/PredicatesTest.java @@ -0,0 +1,40 @@ +package com.netflix.nebula.archrules.gradleplugins; + +import com.tngtech.archunit.core.domain.JavaClass; +import com.tngtech.archunit.core.importer.ClassFileImporter; +import org.gradle.FakeDeprecatedGradleClass; +import org.gradle.FakeDeprecatedGradleMethod; +import org.gradle.internal.InternalGradleClass; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class PredicatesTest { + private static JavaClass scan(Class clazz) { + return new ClassFileImporter().importClass(clazz); + } + + @Test + public void test_gradleClass() { + assertThat(Predicates.gradleClass.test(scan(FakeDeprecatedGradleMethod.class))).isTrue(); + } + + @Test + public void test_deprecatedGradleClass() { + assertThat(Predicates.deprecatedGradleClass.test(scan(FakeDeprecatedGradleMethod.class))).isFalse(); + assertThat(Predicates.deprecatedGradleClass.test(scan(FakeDeprecatedGradleClass.class))).isTrue(); + } + + @Test + public void test_internalGradleClass() { + assertThat(Predicates.internalGradleClass.test(scan(FakeDeprecatedGradleMethod.class))).isFalse(); + assertThat(Predicates.internalGradleClass.test(scan(InternalGradleClass.class))).isTrue(); + } + + @Test + public void test_annotatedWithFileInputAnnotation() { + assertThat(Predicates.areAnnotatedWithFileInputAnnotation.test( + scan(GradleTaskCacheabilityRuleTest.CacheableTaskWithoutPathSensitive.class).getField("inputFile")) + ).isTrue(); + } +} diff --git a/archrules-gradle-plugin-development/src/archRulesTest/java/org/gradle/FakeDeprecatedGradleClass.java b/archrules-gradle-plugin-development/src/archRulesTest/java/org/gradle/FakeDeprecatedGradleClass.java new file mode 100644 index 0000000..4933495 --- /dev/null +++ b/archrules-gradle-plugin-development/src/archRulesTest/java/org/gradle/FakeDeprecatedGradleClass.java @@ -0,0 +1,7 @@ +package org.gradle; + +import org.gradle.api.DefaultTask; + +@Deprecated +public class FakeDeprecatedGradleClass extends DefaultTask { +} diff --git a/archrules-gradle-plugin-development/src/archRulesTest/java/org/gradle/FakeDeprecatedGradleMethod.java b/archrules-gradle-plugin-development/src/archRulesTest/java/org/gradle/FakeDeprecatedGradleMethod.java new file mode 100644 index 0000000..6cb49bb --- /dev/null +++ b/archrules-gradle-plugin-development/src/archRulesTest/java/org/gradle/FakeDeprecatedGradleMethod.java @@ -0,0 +1,8 @@ +package org.gradle; + +public class FakeDeprecatedGradleMethod { + @Deprecated + public static void aMethod(){ + + } +} diff --git a/archrules-gradle-plugin-development/src/archRulesTest/java/org/gradle/internal/InternalGradleClass.java b/archrules-gradle-plugin-development/src/archRulesTest/java/org/gradle/internal/InternalGradleClass.java new file mode 100644 index 0000000..969183f --- /dev/null +++ b/archrules-gradle-plugin-development/src/archRulesTest/java/org/gradle/internal/InternalGradleClass.java @@ -0,0 +1,4 @@ +package org.gradle.internal; + +public class InternalGradleClass { +} diff --git a/archrules-guava/gradle.lockfile b/archrules-guava/gradle.lockfile index ff18201..9545f81 100644 --- a/archrules-guava/gradle.lockfile +++ b/archrules-guava/gradle.lockfile @@ -11,9 +11,10 @@ com.google.j2objc:j2objc-annotations:3.1=archRulesTestArchRulesRuntime,archRules com.netflix.nebula:archrules-deprecation:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime com.netflix.nebula:archrules-joda:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime com.netflix.nebula:archrules-nullability:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime +com.netflix.nebula:archrules-security:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime com.netflix.nebula:archrules-testing-frameworks:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime -com.netflix.nebula:nebula-archrules-core:0.4.0=mainArchRulesRuntime,testArchRulesRuntime -com.netflix.nebula:nebula-archrules-core:0.5.3=archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath +com.netflix.nebula:nebula-archrules-core:0.5.2=mainArchRulesRuntime,testArchRulesRuntime +com.netflix.nebula:nebula-archrules-core:0.5.5=archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath com.tngtech.archunit:archunit:1.4.1=archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath,mainArchRulesRuntime,testArchRulesRuntime net.bytebuddy:byte-buddy:1.17.7=archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath org.apiguardian:apiguardian-api:1.1.2=archRulesTestCompileClasspath diff --git a/archrules-javax/gradle.lockfile b/archrules-javax/gradle.lockfile index f72bd5a..28868c4 100644 --- a/archrules-javax/gradle.lockfile +++ b/archrules-javax/gradle.lockfile @@ -9,10 +9,13 @@ com.netflix.nebula:archrules-joda:0.5.1=archRules com.netflix.nebula:archrules-joda:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime com.netflix.nebula:archrules-nullability:0.5.1=archRules com.netflix.nebula:archrules-nullability:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime +com.netflix.nebula:archrules-security:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime com.netflix.nebula:archrules-testing-frameworks:0.5.1=archRules com.netflix.nebula:archrules-testing-frameworks:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime -com.netflix.nebula:nebula-archrules-core:0.4.0=archRules,mainArchRulesRuntime,testArchRulesRuntime -com.netflix.nebula:nebula-archrules-core:0.5.3=archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesRuntimeClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath +com.netflix.nebula:nebula-archrules-core:0.4.0=archRules +com.netflix.nebula:nebula-archrules-core:0.5.2=mainArchRulesRuntime,testArchRulesRuntime +com.netflix.nebula:nebula-archrules-core:0.5.3=archRulesRuntimeClasspath +com.netflix.nebula:nebula-archrules-core:0.5.5=archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath com.sun.mail:javax.mail:1.6.2=archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath com.tngtech.archunit:archunit:1.4.1=archRules,archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesRuntimeClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath,mainArchRulesRuntime,testArchRulesRuntime jakarta.servlet:jakarta.servlet-api:6.1.0=archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath diff --git a/archrules-joda/gradle.lockfile b/archrules-joda/gradle.lockfile index 9c9efa7..b9ce916 100644 --- a/archrules-joda/gradle.lockfile +++ b/archrules-joda/gradle.lockfile @@ -7,12 +7,13 @@ com.netflix.nebula:archrules-deprecation:0.3.0=archRules com.netflix.nebula:archrules-deprecation:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime com.netflix.nebula:archrules-nullability:0.3.0=archRules com.netflix.nebula:archrules-nullability:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime +com.netflix.nebula:archrules-security:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime com.netflix.nebula:archrules-testing-frameworks:0.3.0=archRules com.netflix.nebula:archrules-testing-frameworks:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime com.netflix.nebula:nebula-archrules-core:0.2.3=archRules com.netflix.nebula:nebula-archrules-core:0.3.0=archRulesRuntimeClasspath -com.netflix.nebula:nebula-archrules-core:0.4.0=mainArchRulesRuntime,testArchRulesRuntime -com.netflix.nebula:nebula-archrules-core:0.5.3=archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath +com.netflix.nebula:nebula-archrules-core:0.5.2=mainArchRulesRuntime,testArchRulesRuntime +com.netflix.nebula:nebula-archrules-core:0.5.5=archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath com.tngtech.archunit:archunit:1.4.1=archRules,archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesRuntimeClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath,mainArchRulesRuntime,testArchRulesRuntime joda-time:joda-time:2.14.0=archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath net.bytebuddy:byte-buddy:1.17.7=archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath diff --git a/archrules-nullability/build.gradle.kts b/archrules-nullability/build.gradle.kts index 4eb2e71..a77deff 100644 --- a/archrules-nullability/build.gradle.kts +++ b/archrules-nullability/build.gradle.kts @@ -19,9 +19,14 @@ dependencies { } java { toolchain { - languageVersion = JavaLanguageVersion.of(11) // must be 11 in order to reference jakarta annotations + languageVersion = JavaLanguageVersion.of(8) } } +tasks.named("compileArchRulesTestJava") { + javaCompiler.set(javaToolchains.compilerFor { + languageVersion.set(JavaLanguageVersion.of(11)) // must be 11 in order to reference jakarta annotations + }) +} dependencyLocking { lockAllConfigurations() } diff --git a/archrules-nullability/gradle.lockfile b/archrules-nullability/gradle.lockfile index 36e0376..ca564d2 100644 --- a/archrules-nullability/gradle.lockfile +++ b/archrules-nullability/gradle.lockfile @@ -8,12 +8,13 @@ com.netflix.nebula:archrules-deprecation:0.3.0=archRules com.netflix.nebula:archrules-deprecation:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime com.netflix.nebula:archrules-joda:0.3.0=archRules com.netflix.nebula:archrules-joda:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime +com.netflix.nebula:archrules-security:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime com.netflix.nebula:archrules-testing-frameworks:0.3.0=archRules com.netflix.nebula:archrules-testing-frameworks:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime com.netflix.nebula:nebula-archrules-core:0.2.3=archRules com.netflix.nebula:nebula-archrules-core:0.3.0=archRulesRuntimeClasspath -com.netflix.nebula:nebula-archrules-core:0.4.0=mainArchRulesRuntime,testArchRulesRuntime -com.netflix.nebula:nebula-archrules-core:0.5.3=archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath +com.netflix.nebula:nebula-archrules-core:0.5.2=mainArchRulesRuntime,testArchRulesRuntime +com.netflix.nebula:nebula-archrules-core:0.5.5=archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath com.tngtech.archunit:archunit:1.4.1=archRules,archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesRuntimeClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath,mainArchRulesRuntime,testArchRulesRuntime jakarta.annotation:jakarta.annotation-api:3.0.0=archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath net.bytebuddy:byte-buddy:1.17.7=archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath diff --git a/archrules-security/gradle.lockfile b/archrules-security/gradle.lockfile index 3dde6f1..5ea3b2f 100644 --- a/archrules-security/gradle.lockfile +++ b/archrules-security/gradle.lockfile @@ -18,7 +18,7 @@ com.netflix.nebula:archrules-testing-frameworks:0.6.0=archRulesArchRulesRuntime, com.netflix.nebula:nebula-archrules-core:0.3.0=archRules com.netflix.nebula:nebula-archrules-core:0.4.0=mainArchRulesRuntime,testArchRulesRuntime com.netflix.nebula:nebula-archrules-core:0.5.2=archRulesRuntimeClasspath -com.netflix.nebula:nebula-archrules-core:0.5.3=archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath +com.netflix.nebula:nebula-archrules-core:0.5.5=archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath com.tngtech.archunit:archunit:1.4.1=archRules,archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesRuntimeClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath,mainArchRulesRuntime,testArchRulesRuntime javax.servlet:javax.servlet-api:3.1.0=archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath net.bytebuddy:byte-buddy:1.17.7=archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath diff --git a/archrules-testing-frameworks/gradle.lockfile b/archrules-testing-frameworks/gradle.lockfile index 50f3dd9..f356a50 100644 --- a/archrules-testing-frameworks/gradle.lockfile +++ b/archrules-testing-frameworks/gradle.lockfile @@ -13,9 +13,11 @@ com.netflix.nebula:archrules-joda:0.4.0=archRules com.netflix.nebula:archrules-joda:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime com.netflix.nebula:archrules-nullability:0.4.0=archRules com.netflix.nebula:archrules-nullability:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime -com.netflix.nebula:nebula-archrules-core:0.3.0=archRules,mainArchRulesRuntime,testArchRulesRuntime +com.netflix.nebula:archrules-security:0.6.0=archRulesArchRulesRuntime,archRulesTestArchRulesRuntime,mainArchRulesRuntime,testArchRulesRuntime +com.netflix.nebula:nebula-archrules-core:0.3.0=archRules com.netflix.nebula:nebula-archrules-core:0.4.0=archRulesRuntimeClasspath -com.netflix.nebula:nebula-archrules-core:0.5.3=archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath +com.netflix.nebula:nebula-archrules-core:0.5.2=mainArchRulesRuntime,testArchRulesRuntime +com.netflix.nebula:nebula-archrules-core:0.5.5=archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath com.tngtech.archunit:archunit:1.4.1=archRules,archRulesArchRulesRuntime,archRulesCompileClasspath,archRulesRuntimeClasspath,archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath,mainArchRulesRuntime,testArchRulesRuntime junit:junit:4.13.2=archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath net.bytebuddy:byte-buddy:1.17.7=archRulesTestArchRulesRuntime,archRulesTestCompileClasspath,archRulesTestRuntimeClasspath diff --git a/build.gradle.kts b/build.gradle.kts index 96babcb..abea24c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,8 +3,8 @@ plugins { } tasks.wrapper { distributionType = Wrapper.DistributionType.BIN - gradleVersion = "9.2.0" - distributionSha256Sum = "df67a32e86e3276d011735facb1535f64d0d88df84fa87521e90becc2d735444" + gradleVersion = "9.2.1" + distributionSha256Sum = "72f44c9f8ebcb1af43838f45ee5c4aa9c5444898b3468ab3f4af7b6076c5bc3f" } dependencyLocking { lockAllConfigurations() @@ -14,4 +14,4 @@ contacts { moniker = "Nebula Plugins Maintainers" github = "nebula-plugins" } -} \ No newline at end of file +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 8bdaf60..f8e1ee3 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 49ab6fc..8a84887 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=df67a32e86e3276d011735facb1535f64d0d88df84fa87521e90becc2d735444 -distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip +distributionSha256Sum=72f44c9f8ebcb1af43838f45ee5c4aa9c5444898b3468ab3f4af7b6076c5bc3f +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/settings.gradle.kts b/settings.gradle.kts index cca3b30..d8d13f1 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,7 +1,7 @@ pluginManagement { plugins { - id("com.netflix.nebula.root") version ("25.+") - id("com.netflix.nebula.library") version ("25.+") + id("com.netflix.nebula.root") version ("25.3.2") + id("com.netflix.nebula.library") version ("25.3.2") } } plugins {