diff --git a/changelog/@unreleased/pr-1260.v2.yml b/changelog/@unreleased/pr-1260.v2.yml new file mode 100644 index 000000000..979f665f0 --- /dev/null +++ b/changelog/@unreleased/pr-1260.v2.yml @@ -0,0 +1,5 @@ +type: fix +fix: + description: Fix baseline-exact-dependencies to no longer resolve compileOnly directly. + links: + - https://github.com/palantir/gradle-baseline/pull/1260 diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineExactDependencies.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineExactDependencies.java index 462e28860..6108ccd63 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineExactDependencies.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineExactDependencies.java @@ -41,6 +41,7 @@ import org.gradle.api.artifacts.ResolvedDependency; import org.gradle.api.artifacts.component.ComponentIdentifier; import org.gradle.api.artifacts.component.ProjectComponentIdentifier; +import org.gradle.api.attributes.Usage; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPluginConvention; import org.gradle.api.tasks.SourceSet; @@ -65,17 +66,26 @@ public void apply(Project project) { .getByName(SourceSet.MAIN_SOURCE_SET_NAME); Configuration compileClasspath = project.getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME); - Configuration compileOnlyClasspath = + Configuration compileOnly = project.getConfigurations().getByName(JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME); - Configuration annotationProcessorClasspath = - project.getConfigurations().getByName(JavaPlugin.ANNOTATION_PROCESSOR_CONFIGURATION_NAME); + Configuration justCompileOnlyResolvable = project.getConfigurations() + .create("baseline-exact-dependencies-compileOnly", conf -> { + conf.setVisible(false); + conf.setCanBeConsumed(false); + conf.extendsFrom(compileOnly); + // Important! this ensures we resolve 'compile' variants rather than 'runtime' + // This is the same attribute that's being set on compileClasspath + conf.getAttributes() + .attribute( + Usage.USAGE_ATTRIBUTE, + project.getObjects().named(Usage.class, Usage.JAVA_API)); + }); project.getTasks().create("checkUnusedDependencies", CheckUnusedDependenciesTask.class, task -> { task.dependsOn(JavaPlugin.CLASSES_TASK_NAME); task.setSourceClasses(mainSourceSet.getOutput().getClassesDirs()); task.dependenciesConfiguration(compileClasspath); - task.sourceOnlyConfiguration(compileOnlyClasspath); - task.sourceOnlyConfiguration(annotationProcessorClasspath); + task.sourceOnlyConfiguration(justCompileOnlyResolvable); // this is liberally applied to ease the Java8 -> 11 transition task.ignore("javax.annotation", "javax.annotation-api"); diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/CheckUnusedDependenciesTask.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/CheckUnusedDependenciesTask.java index 2a85b8926..77e11d722 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/CheckUnusedDependenciesTask.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/CheckUnusedDependenciesTask.java @@ -68,13 +68,6 @@ public final void checkUnusedDependencies() { .collect(Collectors.toSet()); BaselineExactDependencies.INDEXES.populateIndexes(declaredDependencies); - Set necessaryArtifacts = Streams.stream( - sourceClasses.get().iterator()) - .flatMap(BaselineExactDependencies::referencedClasses) - .map(BaselineExactDependencies.INDEXES::classToDependency) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(Collectors.toSet()); Set declaredArtifacts = declaredDependencies.stream() .flatMap(dependency -> dependency.getModuleArtifacts().stream()) .filter(dependency -> @@ -83,6 +76,14 @@ public final void checkUnusedDependencies() { excludeSourceOnlyDependencies(); + Set necessaryArtifacts = Streams.stream( + sourceClasses.get().iterator()) + .flatMap(BaselineExactDependencies::referencedClasses) + .map(BaselineExactDependencies.INDEXES::classToDependency) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toSet()); + Set possiblyUnused = Sets.difference(declaredArtifacts, necessaryArtifacts); getLogger() .debug( diff --git a/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineExactDependenciesTest.groovy b/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineExactDependenciesTest.groovy index c71277916..962497ba9 100644 --- a/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineExactDependenciesTest.groovy +++ b/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineExactDependenciesTest.groovy @@ -26,6 +26,7 @@ class BaselineExactDependenciesTest extends AbstractPluginTest { plugins { id 'java' id 'com.palantir.baseline-exact-dependencies' + id 'com.palantir.baseline' apply false } '''.stripIndent() @@ -43,6 +44,22 @@ class BaselineExactDependenciesTest extends AbstractPluginTest { with('checkUnusedDependencies', 'checkImplicitDependencies', '--stacktrace').build() } + def 'both tasks vacuously pass with no dependencies when entire baseline is applied'() { + when: + buildFile << standardBuildFile + buildFile << """ + repositories { + jcenter() + mavenLocal() // for baseline-error-prone + } + apply plugin: 'com.palantir.baseline' + """.stripIndent() + file('src/main/java/pkg/Foo.java') << minimalJavaFile + + then: + with('checkUnusedDependencies', 'checkImplicitDependencies', '--stacktrace').build() + } + def 'tasks are not run as part of ./gradlew check'() { when: buildFile << standardBuildFile