I'd like to propose adding Gradle build support to the project. This is not a
proposal to remove ant -- ant remains the primary build system. The patch (PR
#4778) adds gradle as an opt-in developer tool that sources its configuration
from ant's build.xml, layering gradle's task graph and caching on top of what
we already have.
**What the patch does**
Gradle wraps ant's existing configuration. You maintain ant as before; gradle
reads from it. The result is a developer experience layer on top of our current
build:
```
$ ./gradlew test --tests org.apache.cassandra.utils.UUIDTest --rerun
BUILD SUCCESSFUL in 2s
27 actionable tasks: 1 executed, 26 up-to-date
```
Compare this to the correct way to run a single test via ant that matches what
CI actually executes and doesn't rebuild unneeded work:
```
$ # human validates that the cache is still valid... did you change the JDK?
Did any file change? Human must maintain this in their head
$ ant -Dant.gen-doc.skip=true \
-Dno-checkstyle=true \
-Dant.gen-doc.skip=true \
-Drat.skip=true \
-Dno-build-test=true \
testclasslist \
-Dtest.timeout=480000 \
-Dtest.classlistprefix=unit \
-Dtest.classlistfile=<(echo org/apache/cassandra/utils/UUIDTest.java)
```
Most developers use `ant test-some` instead because of this complexity, but
`test-some` uses different JVM arguments than `testclasslist` (which is what CI
runs). This means test failures in CI may not reproduce locally because the
developer ran the test differently. With gradle there is one way to run a test;
local and CI do not have different behaviors.
**Why Gradle and not Maven**
This question has come up in every prior discussion, so let me address it
directly.
1. **The ecosystem already chose Gradle.** Accord, Sidecar, and Analytics are
all Gradle projects. Choosing Maven for the server would mean three subprojects
on Gradle and one on Maven. Accord integration is the clearest example of the
problem: today, ant works around Accord being a Gradle project by having Accord
*publish* artifacts to the user's local Maven repository, then ant resolves
them from there. Maven would have the same problem -- it would also need Accord
to publish locally before the server build can proceed. With Gradle, there's no
publish step at all. Gradle understands how to build Accord directly via
composite builds:
```groovy
includeBuild('modules/accord') {
dependencySubstitution {
substitute module('org.apache.cassandra:cassandra-accord') using
project(':accord-core')
}
}
```
Gradle builds Accord from source as part of the server build. No
intermediate publish, no stale local artifacts, no coordination.
2. **Maven forces us into its model; Gradle lets us keep ours.** Over the years
with ant we've grown a number of custom solutions to problems -- custom test
execution, custom artifact assembly, custom dependency handling. These work for
us. Maven's opinionated structure (one artifact per POM, standard lifecycle
phases, rigid directory layout) would require us to restructure the project to
fit Maven's expectations. We'd be fighting the tool. Gradle lets us express our
existing custom workflows naturally while still benefiting from a modern build
system's caching, dependency resolution, and task graph.
3. **Maven can't wrap ant.** The approach in this patch -- gradle sourcing
ant's config so we incrementally adopt without a big-bang rewrite -- isn't
possible with Maven. A Maven migration would require rewriting build
configuration from scratch, which is exactly the kind of disruption that has
killed every prior proposal on this mailing list.
4. **Incremental builds are first-class in Gradle.** Maven's incremental story
requires plugins and is unreliable in practice. Gradle's task avoidance and
build cache are core features.
5. **Gradle version stability -- an honest assessment.** The concern about
Gradle version churn is legitimate. We pin a specific version via the wrapper
(Gradle 9 in this patch), so day-to-day there is no drift. However, when we do
need to upgrade -- for example, to pick up JDK support for a new Java version
-- there is real risk of breaking changes requiring work. If we release
annually, we may need to update Gradle annually, and that could require effort.
Two things that mitigate this: First, Gradle has improved its deprecation
cycle -- they warn for a full major version before removing APIs, giving
upgrade windows. This patch already addressed Accord's Gradle 8 to 9 migration,
which involved deprecation warnings (not breakage) that will become errors in
10.x. Second, AI tooling dramatically lowers the migration cost. This patch
itself was written by Claude opus and it had no issues understanding Gradle's
conventions and generating the correct configuration. Future version upgrades
are well-suited to the same approach -- the tool reads the migration guide,
reads our config, and produces the update.
**Maintenance cost**
I want to be clear-eyed about this: "gradle sources ant" means there is minimal
maintenance overhead *for the current project structure*. If we had this patch
5 years ago, there would have been zero drift in that time. But it's not
zero-maintenance in all scenarios -- if we want to do larger structural changes
(splitting into multiple modules, reorganizing source sets), both systems would
need updates. For the day-to-day reality of how the project evolves, though,
the cost is very low.
**The long-term path**
If gradle proves itself I foresee that we eventual rely on gradle as the source
of truth for builds and we update ant to delegate to gradle. If the community
eventually feels that gradle is getting in our way its isolated and able to
revert; so very low risk.
**What's in this patch and what isn't**
The patch covers the core developer loop:
- Main source compilation with correct JDK flags and `--add-exports`
- Dependency resolution from existing POM files
- ANTLR 3 and JFlex code generation
- Unit, long, burn, distributed, and simulator test suites with correct
JDK-specific JVM args
- All 5 test variants (compression, cdc, latest, oa, system-keyspace-directory)
- Checkstyle (main + test)
- Main JAR and simulator JARs
- Accord composite build (no local publish step)
What's not covered yet:
| Category | What's Missing |
|---|---|
| Packaging | stress.jar, fqltool.jar, sstableloader.jar, dtest-jar,
sources-jar, javadoc-jar |
| Release | bin/src tarballs, checksums, dist directory assembly |
| Publishing | Maven local install and remote deploy with signing |
| Test suites | upgrade dtests, memory tests, stress/fqltool/sstableloader
tests, CQL-specific tests |
| Code coverage | JaCoCo integration |
| Documentation | Javadoc, Asciidoc/Antora |
| Benchmarks | JMH microbench |
| Static analysis | Apache RAT license check |
| Security scanning | OWASP, SonarQube |
This is roughly 52% of ant's total logical outcomes. The intentional scoping
choice was: cover what developers actually use daily, get buy-in on the
approach, then fill in the rest. I'm happy to add any of the above --
particularly release/publishing support -- once the direction is agreed. None
of these are architecturally difficult; they're just additional tasks to wire
up.
**Patch details**
- JIRA: https://issues.apache.org/jira/browse/CASSANDRA-21344
- PR: https://github.com/apache/cassandra/pull/4778
Looking forward to feedback.
---
**Prior mailing list discussions referenced:**
- "[DISCUSS] Build tool" (Feb 2022) -- Aleksei Zotov's proposal to migrate from
ant
- "RFC try for s/ant/gradle/" (Sep 2014) -- Robert Stupp's original Gradle
proposal and prototype
- "[discuss] Modernization of Cassandra build system" (Jun 2015)
- "[DISCUSS] CASSANDRA-17750: Security migration away from Maven Ant Tasks"
(Aug 2022)
- "Any plan to migrate from Ant to Maven?" (May 2020)