Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ apply from: file('gradle/validation/git-status.gradle')
apply from: file('gradle/validation/validate-source-patterns.gradle')
apply from: file('gradle/validation/rat-sources.gradle')
apply from: file('gradle/validation/owasp-dependency-check.gradle')
apply from: file('gradle/validation/dependency-analyze.gradle.kts')
apply from: file('gradle/validation/ecj-lint.gradle')
apply from: file('gradle/validation/gradlew-scripts-tweaked.gradle')
apply from: file('gradle/validation/validate-log-calls.gradle')
Expand Down
11 changes: 11 additions & 0 deletions changelog/unreleased/dagp-SOLR-18302.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc

title: >
Add dependency-analysis (build-health) reporting to the Gradle build in report-not-fail mode,
and apply its safe advice (unused-dependency removals and test-scope corrections)
type: other
authors:
- name: Serhiy Bzhezytskyy
links:
- name: SOLR-18302
url: https://issues.apache.org/jira/browse/SOLR-18302
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,7 @@ opentelemetry-exporter-prometheus = { module = "io.opentelemetry:opentelemetry-e
opentelemetry-runtime-telemetry = { module = "io.opentelemetry.instrumentation:opentelemetry-runtime-telemetry-java17", version.ref = "opentelemetry-runtime-telemetry" }
opentelemetry-sdk = { module = "io.opentelemetry:opentelemetry-sdk", version.ref = "opentelemetry" }
opentelemetry-sdk-extension-autoconfigure = { module = "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure", version.ref = "opentelemetry" }
opentelemetry-sdk-extension-autoconfigure-spi = { module = "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi", version.ref = "opentelemetry" }
opentelemetry-sdk-metrics = { module = "io.opentelemetry:opentelemetry-sdk-metrics", version.ref = "opentelemetry" }
opentelemetry-sdk-testing = { module = "io.opentelemetry:opentelemetry-sdk-testing", version.ref = "opentelemetry" }
opentelemetry-sdk-trace = { module = "io.opentelemetry:opentelemetry-sdk-trace", version.ref = "opentelemetry" }
Expand Down
7 changes: 5 additions & 2 deletions gradle/validation/dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,11 @@ allprojects {
// Resolve and update locks only if --write-locks explicitly included
// This may not be the case where this task is added as a dependency, like for "dependencies" task
project.configurations.findAll {
// Add any custom filtering on the configurations to be resolved
it.canBeResolved
// Add any custom filtering on the configurations to be resolved.
// Skip the dependency-analysis plugin's synthetic configurations (marked with "dagp.*"
// attributes); they are not meant to be resolved and would fail lock-file generation.
it.canBeResolved &&
!it.attributes.keySet().any {attr -> attr.name.startsWith("dagp.")}
}.each {it.resolve()}
}
}
Expand Down
66 changes: 66 additions & 0 deletions gradle/validation/dependency-analyze.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import com.autonomousapps.DependencyAnalysisExtension

configure<DependencyAnalysisExtension> {
issues {
project(":solr:ui") {
onUnusedDependencies {
severity("ignore")
}
onUsedTransitiveDependencies {
severity("ignore")
}
onIncorrectConfiguration {
severity("ignore")
}
}

project(":solr:solrj-jetty") {
onUnusedDependencies {
exclude(":solr:solrj")
}
}

project(":solr:modules:jwt-auth") {
onDuplicateClassWarnings {
severity("ignore")
}
}

all {
// Report advice as warnings rather than failing the build: several categories
// (api-vs-implementation promotions, some test-scope changes) need case-by-case
// human judgment. Run `gradlew buildHealth` to see the current advice.
onAny {
severity("warn")
}
onUnusedDependencies {
exclude(
"org.jspecify:jspecify",
"com.google.code.findbugs:jsr305",
"com.google.errorprone:error_prone_annotations",
)
}
}
}
}

tasks.named("check").configure {
dependsOn(tasks.named("buildHealth"))
}
15 changes: 15 additions & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,24 @@ pluginManagement {
includeBuild("build-tools/build-infra")
}

// The dependency-analysis plugin (build-health) bundles a kotlin-metadata-jvm that can't yet parse
// Kotlin 2.4.0 metadata, so it fails ExplodeJarTask on the :solr:ui (Compose/KMP) module
// ("Provided Metadata instance has version 2.4.0, while maximum supported version is 2.3.0").
// Tracked upstream in autonomousapps/dependency-analysis-gradle-plugin#1661; until that ships,
// force the metadata library to match Solr's Kotlin version so DAGP can analyze the UI module.
buildscript {
configurations.classpath {
resolutionStrategy {
force "org.jetbrains.kotlin:kotlin-metadata-jvm:2.4.0"
}
}
}

plugins {
id 'com.gradle.develocity' version '4.2.2'
id 'com.gradle.common-custom-user-data-gradle-plugin' version '2.4.0'
id 'com.autonomousapps.build-health' version '3.16.0'
id 'org.jetbrains.kotlin.multiplatform' version '2.4.0' apply false
}

apply from: file('gradle/develocity.gradle')
Expand Down
1 change: 0 additions & 1 deletion solr/api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ dependencies {
implementation libs.semver4j.semver4j

testImplementation project(':solr:test-framework')
testImplementation project(':solr:api')
testImplementation libs.junit.junit
testImplementation libs.hamcrest.hamcrest
testImplementation libs.apache.lucene.testframework
Expand Down
10 changes: 7 additions & 3 deletions solr/benchmark/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ task echoCp {
}

dependencies {
implementation project(':solr:test-framework')
api project(':solr:test-framework')
implementation project(':solr:core')
implementation project(':solr:solrj')
implementation project(':solr:solrj-jetty')
api project(':solr:solrj')
api project(':solr:solrj-jetty')
implementation project(':solr:solrj-streaming')

implementation libs.apache.lucene.core
Expand All @@ -56,4 +56,8 @@ dependencies {
implementation libs.slf4j.api
runtimeOnly libs.lmax.disruptor
annotationProcessor libs.openjdk.jmh.generatorannprocess

testAnnotationProcessor libs.openjdk.jmh.generatorannprocess
testImplementation libs.carrotsearch.randomizedtesting.runner
testImplementation libs.junit.junit
}
8 changes: 4 additions & 4 deletions solr/benchmark/gradle.lockfile
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,11 @@ jakarta.ws.rs:jakarta.ws.rs-api:4.0.0=jarValidation,runtimeClasspath,testRuntime
jakarta.xml.bind:jakarta.xml.bind-api:4.0.2=jarValidation,runtimeClasspath,testRuntimeClasspath
javax.inject:javax.inject:1=annotationProcessor,errorprone,testAnnotationProcessor
junit:junit:4.13.2=compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
net.sf.jopt-simple:jopt-simple:5.0.4=annotationProcessor,compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
net.sf.jopt-simple:jopt-simple:5.0.4=annotationProcessor,compileClasspath,jarValidation,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
org.antlr:antlr4-runtime:4.13.2=jarValidation,runtimeClasspath,testRuntimeClasspath
org.apache.commons:commons-exec:1.6.0=jarValidation,runtimeClasspath,testRuntimeClasspath
org.apache.commons:commons-lang3:3.20.0=jarValidation,runtimeClasspath,testRuntimeClasspath
org.apache.commons:commons-math3:3.6.1=annotationProcessor,compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.commons:commons-math3:3.6.1=annotationProcessor,compileClasspath,jarValidation,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
org.apache.curator:curator-client:5.9.0=compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.curator:curator-framework:5.9.0=compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.curator:curator-test:5.9.0=jarValidation,runtimeClasspath,testRuntimeClasspath
Expand Down Expand Up @@ -154,8 +154,8 @@ org.junit.jupiter:junit-jupiter-api:5.6.2=jarValidation,runtimeClasspath,testRun
org.junit.platform:junit-platform-commons:1.6.2=jarValidation,runtimeClasspath,testRuntimeClasspath
org.junit:junit-bom:5.6.2=jarValidation,runtimeClasspath,testRuntimeClasspath
org.locationtech.spatial4j:spatial4j:0.8=jarValidation,runtimeClasspath,testRuntimeClasspath
org.openjdk.jmh:jmh-core:1.37=annotationProcessor,compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.openjdk.jmh:jmh-generator-annprocess:1.37=annotationProcessor
org.openjdk.jmh:jmh-core:1.37=annotationProcessor,compileClasspath,jarValidation,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
org.openjdk.jmh:jmh-generator-annprocess:1.37=annotationProcessor,testAnnotationProcessor
org.opentest4j:opentest4j:1.2.0=jarValidation,runtimeClasspath,testRuntimeClasspath
org.ow2.asm:asm-commons:9.10.1=jarValidation,runtimeClasspath,testRuntimeClasspath
org.ow2.asm:asm-tree:9.10.1=jarValidation,runtimeClasspath,testRuntimeClasspath
Expand Down
19 changes: 2 additions & 17 deletions solr/core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ dependencies {
}

implementation libs.swagger3.annotations.jakarta

// Export these dependencies so that they're imported transitively by
// other modules.

Expand All @@ -46,7 +45,7 @@ dependencies {

api project(':solr:api')
api project(':solr:solrj')
implementation project(':solr:solrj-jetty')
api project(':solr:solrj-jetty')
api project(':solr:solrj-zookeeper')
api project(':solr:solrj-streaming')

Expand All @@ -62,12 +61,10 @@ dependencies {
implementation libs.jersey.core.common
implementation libs.jersey.core.server
implementation libs.hk2.api

implementation libs.jakarta.inject.api
implementation libs.jakarta.ws.rsapi
implementation libs.jakarta.annotation.api
implementation libs.jakarta.servlet.api

runtimeOnly libs.apache.lucene.analysis.kuromoji
runtimeOnly libs.apache.lucene.analysis.nori
runtimeOnly libs.apache.lucene.analysis.phonetic
Expand All @@ -83,31 +80,25 @@ dependencies {
implementation libs.apache.lucene.sandbox
implementation libs.apache.lucene.spatialextras
implementation libs.apache.lucene.suggest

// Collections & lang utilities
implementation libs.google.guava
implementation libs.apache.commons.lang3
implementation libs.apache.commons.math3
implementation libs.commonsio.commonsio
implementation libs.carrotsearch.hppc

implementation(libs.benmanes.caffeine) {transitive = false}

implementation libs.commonscodec.commonscodec

implementation libs.commonscli.commonscli

implementation libs.locationtech.spatial4j

implementation libs.fasterxml.jackson.core.annotations
implementation libs.fasterxml.jackson.core.core
implementation libs.fasterxml.jackson.core.databind
implementation libs.fasterxml.jackson.dataformat.smile
implementation libs.fasterxml.jackson.dataformat.cbor

implementation libs.eclipse.jetty.client
implementation libs.eclipse.jetty.http
implementation libs.eclipse.jetty.io
implementation libs.eclipse.jetty.util

// ZooKeeper
Expand All @@ -127,7 +118,6 @@ dependencies {
implementation(libs.apache.zookeeper.jute) {
exclude group: 'org.apache.yetus', module: 'audience-annotations'
}
testImplementation variantOf(libs.apache.zookeeper.zookeeper) {classifier 'tests'}

// required for instantiating a Zookeeper server (for embedding ZK)
runtimeOnly libs.xerial.snappy.java
Expand All @@ -139,7 +129,6 @@ dependencies {

// StatsComponents percentiles
implementation libs.tdunning.tdigest

// OpenTelemetry
api libs.opentelemetry.api
implementation libs.opentelemetry.context
Expand All @@ -154,7 +143,6 @@ dependencies {
implementation libs.opentelemetry.runtime.telemetry

implementation libs.apache.commons.exec

implementation libs.apache.log4j.api
implementation libs.apache.log4j.core
runtimeOnly libs.apache.log4j.slf4j2impl
Expand All @@ -173,7 +161,6 @@ dependencies {
compileOnly libs.stephenc.jcip.annotations

implementation libs.j256.simplemagic

// -- Test Dependencies

testRuntimeOnly libs.slf4j.jcloverslf4j
Expand All @@ -182,15 +169,13 @@ dependencies {

testRuntimeOnly project(':solr:modules:analysis-extras')

testImplementation project(':solr:core')
testImplementation project(':solr:test-framework')

testImplementation libs.apache.lucene.testframework

testImplementation libs.eclipse.jetty.io
testImplementation libs.eclipse.jetty.server
testImplementation libs.eclipse.jetty.ee10.servlet
testImplementation libs.eclipse.jetty.util
testImplementation libs.jakarta.servlet.api
testImplementation libs.carrotsearch.randomizedtesting.runner
testImplementation libs.junit.junit
testImplementation libs.hamcrest.hamcrest
Expand Down
9 changes: 5 additions & 4 deletions solr/cross-dc-manager/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ description = 'Cross-DC Manager'

dependencies {
implementation platform(project(':platform'))
implementation project(':solr:core')
implementation project(':solr:solrj')
api project(':solr:core')
api project(':solr:solrj')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's confusing to me why solrj is listed here at all (whatever configuration scope). solr-core has an "api" config dependency on solrj... thus this means solrJ is exposed at equivalent scope to whoever consumed solr-core. The subproject here is depending on solr-core... so then why also mention solrj at all?

What I'm talking about is probably tangential to this PR because you didn't change the scopes I'm talking about. Note that many of our dependency declarations are redundant due to cutterslade not understanding the nuance of gradle's "api". I'm hoping we can remove these redundant declarations and maybe the dagp thing you are adding could help us identify redundancies?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question, and it's actually the opposite of redundant here — cross-dc-manager uses solrj directly (CloudSolrClient, UpdateRequest, SolrRequest, etc. in ~4 files), so declaring it is the right call rather than leaning on the transitive api from core. The Gradle guidance is "declare what you use directly," so you don't break when core's internals shift.

And yeah — DAGP is exactly the tool for what you're after. It flags both directions: unused declarations you can drop, and transitives you use directly but haven't declared. For this one it agrees with keeping solrj (doesn't flag it for removal). So it should help find the genuinely-redundant cutterslade leftovers without touching the legit direct declarations.

Happy to do a pass on the redundant ones as a follow-up if useful.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We agree there's a judgement call to make a dependency "api" instead of "implementation"; we're not doing it willy-nilly or simply because some tool found one public API signature using the dependency. If we are diligent about this (I think we are), then why not rely on this judgement on the consuming end to not be redundant? Otherwise, what's the point of "api" at all if we don't take advantage of it.

Case in point: There's no way in hell that SolrJ will stop being a dependency of Solr-core. Any consumer of solr-core will consume solrJ. Even if for some other example where it'a "api" today but we change our mind... well so what? Consumer will find out (won't compile) and add the dependency explicitly then.

@serhiy-bzhezytskyy serhiy-bzhezytskyy Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strong agree — this is a human call, not the tool's. dagp wouldn't flag it for removal (it'd keep solrj — cross-dc uses it directly). I can do a manual pass and put up a PR — WDYT?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I think I'd prefer that you iterate on the part1 PR; no need for additional ones IMO.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good — will iterate on #4612.

implementation project(':solr:solrj-zookeeper')
implementation project(':solr:modules:cross-dc')
api project(':solr:modules:cross-dc')
implementation project(':solr:modules:opentelemetry')

implementation platform(libs.opentelemetry.bom)
Expand Down Expand Up @@ -72,7 +72,8 @@ dependencies {
classifier = "test"
}
}
testImplementation(libs.apache.kafka.clients) {
// EmbeddedKafkaCluster loads org.apache.kafka.test.TestCondition from this at runtime
testRuntimeOnly(libs.apache.kafka.clients) {
artifact {
classifier = "test"
}
Expand Down
8 changes: 4 additions & 4 deletions solr/cross-dc-manager/gradle.lockfile
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,11 @@ org.eclipse.jetty.ee10:jetty-ee10-servlets:12.1.10=solrPlatformLibs
org.eclipse.jetty.ee10:jetty-ee10-webapp:12.1.10=solrPlatformLibs
org.eclipse.jetty.ee:jetty-ee-webapp:12.1.10=solrPlatformLibs
org.eclipse.jetty.http2:jetty-http2-client-transport:12.1.10=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath
org.eclipse.jetty.http2:jetty-http2-client:12.1.10=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty.http2:jetty-http2-common:12.1.10=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty.http2:jetty-http2-hpack:12.1.10=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty.http2:jetty-http2-client:12.1.10=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty.http2:jetty-http2-common:12.1.10=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty.http2:jetty-http2-hpack:12.1.10=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty.http2:jetty-http2-server:12.1.10=jarValidation,solrPlatformLibs,testRuntimeClasspath
org.eclipse.jetty:jetty-alpn-client:12.1.10=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-alpn-client:12.1.10=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-alpn-java-client:12.1.10=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath
org.eclipse.jetty:jetty-alpn-java-server:12.1.10=jarValidation,solrPlatformLibs,testRuntimeClasspath
org.eclipse.jetty:jetty-alpn-server:12.1.10=jarValidation,solrPlatformLibs,testRuntimeClasspath
Expand Down
3 changes: 1 addition & 2 deletions solr/modules/analysis-extras/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ description = 'Additional analysis components'
dependencies {
api project(':solr:core')

implementation project(':solr:solrj')

api project(':solr:solrj')
implementation libs.ibm.icu.icu4j
implementation libs.apache.lucene.analysis.icu
runtimeOnly libs.apache.lucene.analysis.morfologik
Expand Down
Loading