Skip to content

SOLR-18289: Upgrade Gradle build to 9.6.0#4539

Open
serhiy-bzhezytskyy wants to merge 3 commits into
apache:mainfrom
serhiy-bzhezytskyy:gradle-9-upgrade
Open

SOLR-18289: Upgrade Gradle build to 9.6.0#4539
serhiy-bzhezytskyy wants to merge 3 commits into
apache:mainfrom
serhiy-bzhezytskyy:gradle-9-upgrade

Conversation

@serhiy-bzhezytskyy

Copy link
Copy Markdown

https://issues.apache.org/jira/browse/SOLR-18289

Description

Upgrades Solr's build from Gradle 8.10 to 9.6.0 (the current stable Gradle release). Solr is currently a full major version behind; this brings the build onto Gradle 9.x. The Java baseline is unchanged (Java 21) — this is purely a build-tool upgrade.

For reference, Lucene already completed the same 8 -> 9 migration and is on 9.6.0, so the migration path is well-trodden. (As discussed on the dev@ thread, Solr's build is independent of Lucene's; the one place version alignment helps is the lucene-dev composite build, which uses includeBuild against a local Lucene checkout.)

Changes

Gradle 8 -> 9 API migrations:

  • Wrapper + version catalog -> 9.6.0.
  • archivesBaseName -> base { archivesName }; sourceCompatibility / targetCompatibility moved under the java { } extension.
  • Project.exec / Project.javaexec are removed in Gradle 9 -> inject ExecOperations (the quietExec helper, ChangesToHtmlTask, CheckBrokenLinksTask, JavaCCTask).
  • ProjectDependency.dependencyProject -> dep / project(dep.path).
  • Archive/copy file modes -> dirPermissions / filePermissions / permissions { unix(...) }.
  • RAT classpath resolved at configuration time (Gradle 9 forbids resolving configurations at execution time).
  • jar-checks: drop the now-forbidden setCanBeConsumed(true) on a copied resolvable configuration.
  • render-javadoc: findRenderTasksInDependencies() made non-private (Groovy 4 dispatch on decorated task instances).
  • rat-sources: explicit import groovy.xml.XmlParser (Groovy 4).
  • webapp: webAppDirName -> from("web").

Other:

  • Dependency analysis: the ca.cutterslade.analyze plugin has no Gradle-9-compatible release; with Gradle dependency locking enabled (which Solr uses) it produces false-positive "unused dependency" failures across modules — see gradle-dependency-analyze#810. So this PR removes it — matching Lucene main, which carries no dependency-analysis plugin. Per the dev@ thread, adopting a Gradle-9-native replacement (e.g. the autonomousapps Dependency Analysis Gradle Plugin) is left as a separate follow-up so it doesn't block the build-tool upgrade.
  • netty-tcnative: the catalog pinned netty = 4.2.15 but netty-tcnative = 2.0.75; the netty BOM forces 2.0.77 in one module, so two versions resolved. Aligned the pin to 2.0.77 and updated the license checksum files.
  • The wrapper-bootstrap JDK upper bound is raised 23 -> 25 in a separate commit so it can be dropped easily if considered out of scope.

Lockfiles regenerated on Java 21.

Testing

Verified on Eclipse Temurin 21:

  • ./gradlew check (compile + all lint/validation: RAT, jar-checks, forbidden-apis, spotless, javadoc, broken-links, ecj) passes.
  • Per-module test suites pass. The full parallel ./gradlew test is intermittently flaky on a developer machine independent of this change (e.g. SolrProcessManagerTest spawns child JVMs and binds ports — a TOCTOU race; CollectionsAPISolrJTest ZK-watcher timing); the same failures reproduce on an unmodified main checkout and pass on rerun / in isolation.

AI assistance disclosure

Per Solr's AGENTS.md / how-to-contribute guidance: this change was prepared with the assistance of an AI coding agent and has been reviewed by me for correctness, scope, and alignment with Solr's build conventions.

@serhiy-bzhezytskyy

Copy link
Copy Markdown
Author

Pushed a fix for the Docker build failure — missed several Project.exec() calls in solr/docker/build.gradle that need to use injected ExecOperations in Gradle 9. Migrated dockerBuild, dockerTag, dockerPush, and getBuildxBuilderInfo() to use getExecOperations().exec { }.

Ready for CI re-approval.

@serhiy-bzhezytskyy

Copy link
Copy Markdown
Author

Fixed scoping issue in DockerBuildTask — task action methods don't have access to build script top-level variables, so now passing them as task properties. Verified locally that the exec() migration works (task runs, only fails on missing Docker daemon which is environment-specific).

@dsmiley

dsmiley commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

So far looks good on my machine. runDev works. Boy the docker/build.gradle changes are extensive.

Copilot AI left a comment

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.

Pull request overview

Upgrades Solr’s build tooling from Gradle 8.10 to Gradle 9.6.0 and applies required Gradle 9 API migrations across build logic (task execution, archive permissions, Java plugin configuration), along with lockfile regeneration and a small dependency alignment (netty-tcnative).

Changes:

  • Bump Gradle wrapper/version catalog to 9.6.0 and migrate build scripts off removed Gradle 9 APIs (e.g., Project.exec/javaexec, archivesBaseName, file mode APIs).
  • Remove the ca.cutterslade.analyze dependency-analysis plugin and adjust related build wiring/lockfiles.
  • Align netty-tcnative pin to 2.0.77.Final and update license checksum files; regenerate Gradle dependency lockfiles.

Reviewed changes

Copilot reviewed 64 out of 65 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
solr/webapp/gradle.lockfile Lockfile regen + netty-tcnative alignment and config set changes.
solr/webapp/build.gradle Gradle 9 WAR configuration migration (webAppDirNamefrom("web")).
solr/ui/gradle.lockfile Lockfile regen with added regen hint comment.
solr/test-framework/gradle.lockfile Lockfile regen; removes permit* configurations from lock state.
solr/test-framework/build.gradle Drops permitUnusedDeclared usage (plugin removed).
solr/solrj/gradle.lockfile Lockfile regen with updated configuration sets.
solr/solrj-zookeeper/gradle.lockfile Lockfile regen + netty-tcnative alignment.
solr/solrj-streaming/gradle.lockfile Lockfile regen + netty-tcnative alignment.
solr/solrj-jetty/gradle.lockfile Lockfile regen with updated configuration sets.
solr/solr-ref-guide/gradle.lockfile Lockfile regen + netty-tcnative alignment.
solr/server/gradle.lockfile Lockfile regen + netty-tcnative alignment.
solr/packaging/gradle.lockfile Lockfile regen with added regen hint comment.
solr/packaging/build.gradle Gradle 9 API migrations (project reference, permissions API, task class updates).
solr/modules/sql/gradle.lockfile Lockfile regen + netty-tcnative alignment.
solr/modules/scripting/gradle.lockfile Lockfile regen + netty-tcnative alignment.
solr/modules/opentelemetry/gradle.lockfile Lockfile regen with updated configuration sets.
solr/modules/ltr/gradle.lockfile Lockfile regen with updated configuration sets.
solr/modules/language-models/gradle.lockfile Lockfile regen with updated configuration sets.
solr/modules/langid/gradle.lockfile Lockfile regen with updated configuration sets.
solr/modules/jwt-auth/gradle.lockfile Lockfile regen; removes prior constraintsOnly workaround.
solr/modules/jwt-auth/build.gradle Removes old dependency-analyze plugin workaround; uses platform constraints via implementation platform(...).
solr/modules/gradle.lockfile Lockfile regen with added regen hint comment.
solr/modules/gcs-repository/gradle.lockfile Lockfile regen with updated configuration sets.
solr/modules/extraction/gradle.lockfile Lockfile regen + netty-tcnative alignment.
solr/modules/cuvs/gradle.lockfile Lockfile regen + netty-tcnative alignment.
solr/modules/cross-dc/gradle.lockfile Lockfile regen with updated configuration sets.
solr/modules/clustering/gradle.lockfile Lockfile regen with updated configuration sets.
solr/modules/analysis-extras/gradle.lockfile Lockfile regen with updated configuration sets.
solr/licenses/netty-tcnative-classes-2.0.77.Final.jar.sha1 Add checksum for new netty-tcnative artifact.
solr/licenses/netty-tcnative-classes-2.0.75.Final.jar.sha1 Remove checksum for old netty-tcnative artifact.
solr/licenses/netty-tcnative-boringssl-static-2.0.77.Final.jar.sha1 Add checksum for new netty-tcnative artifact.
solr/licenses/netty-tcnative-boringssl-static-2.0.75.Final.jar.sha1 Remove checksum for old netty-tcnative artifact.
solr/gradle.lockfile Lockfile regen with added regen hint comment.
solr/example/gradle.lockfile Lockfile regen with added regen hint comment.
solr/documentation/gradle.lockfile Lockfile regen with added regen hint comment.
solr/docker/gradle.lockfile Lockfile regen with added regen hint comment.
solr/docker/build.gradle Gradle 9 task execution migration (ExecOperations), plus docker task refactors.
solr/distribution/gradle.lockfile Lockfile regen; removes signatures-related lock state.
solr/cross-dc-manager/gradle.lockfile Lockfile regen + netty-tcnative alignment.
solr/core/gradle.lockfile Lockfile regen + netty-tcnative alignment.
solr/benchmark/gradle.lockfile Lockfile regen + netty-tcnative alignment.
solr/api/gradle.lockfile Lockfile regen with updated configuration sets.
settings-gradle.lockfile Lockfile regen with added regen hint comment.
platform/gradle.lockfile Lockfile regen with added regen hint comment.
gradle/wrapper/gradle-wrapper.properties Gradle wrapper bump to 9.6.0.
gradle/validation/rat-sources.gradle Gradle 9-compatible RAT classpath resolution (avoid execution-time resolution).
gradle/validation/owasp-dependency-check.gradle Adjust OWASP skipConfigurations (plugin removal follow-up).
gradle/validation/jar-checks.gradle Gradle 9-compatible configuration flags (don’t set canBeConsumed).
gradle/validation/dependency-analyze.gradle Remove dependency-analyze integration script (plugin removed).
gradle/validation/check-broken-links.gradle Replace project.exec usage with injected ExecOperations.
gradle/solr/packaging.gradle Gradle 9 ProjectDependency API migration (dependencyProjectpath).
gradle/maven/defaults-maven.gradle Gradle 9 archives naming migration (archivesBaseNamebase.archivesName).
gradle/libs.versions.toml Bump Gradle to 9.6.0; remove cutterslade-analyze plugin; align netty-tcnative version.
gradle/java/javac.gradle Move source/target compatibility into java {} extension (Gradle 9 style).
gradle/java/jar-manifest.gradle Use project.java.*Compatibility accessors after compatibility migration.
gradle/hacks/gradle-archives.gradle Migrate archive/copy modes to Gradle 9 permissions API.
gradle/globals.gradle Replace project.exec usage in helper with ExecOperations.
gradle/generation/javacc.gradle Replace project.javaexec with injected ExecOperations.javaexec.
gradle/documentation/render-javadoc.gradle Gradle 9 ProjectDependency API migration + Groovy 4 task dispatch adjustment.
gradle/documentation/changes-to-html.gradle Replace project.exec with injected ExecOperations.
gradle.lockfile Root lockfile regen with added regen hint comment.
changelog/unreleased/SOLR-18289-gradle-9.yml Changelog entry for the Gradle 9.6.0 upgrade.
build.gradle Remove dependency-analyze plugin application and wiring.
build-tools/build-infra/src/main/java/org/apache/lucene/gradle/WrapperDownloader.java Raise wrapper-bootstrap JDK upper bound (23 → 25).
Comments suppressed due to low confidence (2)

solr/docker/build.gradle:339

  • DockerPushTask.pushDockerImage() uses getSolrTgzConfiguration(), dockerImageDistSuffix, baseDockerImage, and dockerImageName, all of which are script-local closures/vars and won’t be visible from inside the task class. Read these from task inputs and resolve the tgz configuration by name via the Project instead.
      def solrTgzConfiguration = getSolrTgzConfiguration()
      getExecOperations().exec {
        standardInput = solrTgzConfiguration.singleFile.newDataInputStream()
        commandLine "docker", "buildx", "build",
            "-f", "solr-${-> project.version}${dockerImageDistSuffix}/docker/Dockerfile",
            "--platform", platformValue,
            "--build-arg", "BASE_IMAGE=${-> baseDockerImage}",
            "--tag", dockerImageName,
            "--push",

solr/docker/build.gradle:349

  • The non-multi-platform push path (and log lines) reference dockerImageName, which is not defined in the task class scope. Use the value pulled from inputs.properties so both branches work.
      project.logger.lifecycle("Solr Docker Multi-Platform Image Pushed: \t$dockerImageName")
      project.logger.lifecycle("\tPlatforms: \t$platformValue")
    } else {
      getExecOperations().exec {
        commandLine "docker", "push", dockerImageName
      }
      project.logger.lifecycle("Solr Docker Image Pushed: \t$dockerImageName")
    }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread solr/docker/build.gradle Outdated
Comment thread solr/docker/build.gradle
Comment thread solr/docker/build.gradle Outdated
Comment thread solr/docker/build.gradle Outdated
Comment thread solr/docker/build.gradle Outdated
@serhiy-bzhezytskyy

Copy link
Copy Markdown
Author

Good call on the docker/build.gradle size, @dsmiley — I'd over-engineered it by converting the tasks into typed task classes, which also broke at runtime (the Copilot review caught the same script-local scoping issues, and CI hit it on dockerTag).

I've reworked it to the minimal change: inject ExecOperations via a small holder — the same pattern already used in gradle/globals.gradle — and route the existing exec { } calls through it. The task definitions are otherwise untouched. The diff is now +17/-9 instead of the previous ~380 lines.

Verified locally (Docker daemon running): dockerBuild builds the image and dockerTag tags it successfully.

@serhiy-bzhezytskyy

Copy link
Copy Markdown
Author

Dropped the "Allow building with JDK up to 25" commit to keep this PR focused on the Gradle 9.6.0 upgrade (Java 21 baseline).

For the record on JDK 25: I tested it — Gradle 9.6.0 and javac compilation work fine, but the pinned google-java-format 1.18.1 throws NoSuchMethodError on JDK 25's javac internals (a known google-java-format limitation, resolved in 1.34.0+; I verified 1.35.0 works). Raising the JDK bound therefore needs a separate google-java-format upgrade, which also reformats many files repo-wide — so it's better as its own follow-up. Happy to propose that separately.

The wrapper bound stays at the existing 21–23 here.

Migrate Solr's build from Gradle 8.10 to 9.6.0, matching the version
already used by Lucene main. Java baseline stays at 21; this is purely a
build-tool upgrade.

Gradle 8 -> 9 API migrations:
- Wrapper and version catalog bumped to 9.6.0.
- archivesBaseName -> base { archivesName }; sourceCompatibility/
  targetCompatibility moved under the java { } extension.
- Project.exec/javaexec are removed in Gradle 9: inject ExecOperations
  into the quietExec helper (globals.gradle), ChangesToHtmlTask,
  CheckBrokenLinksTask and JavaCCTask.
- ProjectDependency.dependencyProject -> dep / project(dep.path).
- Archive/copy file modes -> dirPermissions/filePermissions/permissions
  { unix(...) }.
- RAT: resolve the rat classpath at configuration time (Gradle 9 forbids
  resolving configurations at execution time).
- jar-checks: drop the now-forbidden setCanBeConsumed(true) on a copied
  resolvable configuration.
- render-javadoc: make findRenderTasksInDependencies() non-private so the
  decorated task instance can call it under Groovy 4.
- rat-sources: explicit import of groovy.xml.XmlParser (Groovy 4).
- webapp: webAppDirName -> from("web").

Remove ca.cutterslade.analyze dependency analysis:
- The plugin is incompatible with Gradle 9 (no released version supports
  it; see gradle-dependency-analyze issue apache#810, false positives under
  dependency locking) and fails every module. Lucene main carries no
  dependency-analysis plugin, so drop it here too rather than block the
  upgrade. Removes dependency-analyze.gradle and the per-module
  permitUnusedDeclared / permitTestUnusedDeclared declarations.

Lockfiles regenerated on JDK 21.
The version catalog pinned netty = 4.2.15.Final but netty-tcnative =
2.0.75.Final. The netty 4.2.15 BOM (pulled into :solr:modules:opentelemetry
via grpc-netty) forces tcnative to 2.0.77.Final there, while other modules
resolved the catalog-pinned 2.0.75 — so two tcnative versions resolved
across the build. Under Gradle 9 this surfaced as a checkDanglingLicenseFiles
warning (the 2.0.77 license files are required by opentelemetry's
validateJarChecksums but not collected by the dangling-file check).

Align the catalog pin to 2.0.77.Final so the whole build resolves a single
version; swap the 2.0.75 license checksum files for 2.0.77 ones and
regenerate lockfiles.
Project.exec() and Project.javaexec() are removed in Gradle 9. Inject
ExecOperations via a small holder (the same pattern used in
gradle/globals.gradle) and route the existing exec { } calls through it,
keeping the task definitions otherwise unchanged.

This fixes the Docker image build failure in CI.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants