Elasticsearch is built using the [Gradle](https://gradle.org/) open source build tools.
This document provides a general guidelines for using and working on the elasticsearch build logic.
## Build logic organisation
The Elasticsearch project contains 3 build-related projects that are included into the Elasticsearch build as a [composite build](https://docs.gradle.org/current/userguide/composite_builds.html).
### `build-conventions`
This project contains build conventions that are applied to all elasticsearch projects.
### `build-tools`
This project contains all build logic that we publish for third party elasticsearch plugin authors.
We provide the following plugins:
-`elasticsearch.esplugin` - A gradle plugin for building an elasticsearch plugin.
-`elasticsearch.testclusters` - A gradle plugin for setting up es clusters for testing within a build.
This project is published as part of the elasticsearch release and accessible by
Tony Robalik has compiled a good list of rules that aligns with ours when it comes to writing and maintaining elasticsearch
gradle build logic at http://autonomousapps.com/blog/rules-for-gradle-plugin-authors.html.
Our current build does not yet tick off all those rules everywhere but the ultimate goal is to follow these principles.
The reasons for following those rules besides better readability or maintenance are also the goal to support newer gradle
features that we will benefit from in terms of performance and reliability.
E.g. [configuration-cache support](https://github.com/elastic/elasticsearch/issues/57918), [Project Isolation]([https://gradle.github.io/configuration-cache/#project_isolation) or
[predictive test selection](https://gradle.com/gradle-enterprise-solutions/predictive-test-selection/)
(see https://github.com/elastic/elasticsearch/blob/main/build-tools/src/testFixtures/groovy/org/elasticsearch/gradle/fixtures/AbstractGradleFuncTest.groovy)
The elasticsearch build makes use of the [task avoidance API](https://docs.gradle.org/current/userguide/task_configuration_avoidance.html) to keep the configuration time of the build low.
When declaring tasks (in build scripts or custom plugins) this means that we want to _register_ a task like:
tasks.register('someTask') { ... }
instead of eagerly _creating_ the task:
task someTask { ... }
The major difference between these two syntaxes is, that the configuration block of an registered task will only be executed when the task is actually created due to the build requires that task to run. The configuration block of an eagerly created tasks will be executed immediately.
By actually doing less in the gradle configuration time as only creating tasks that are requested as part of the build and by only running the configurations for those requested tasks, using the task avoidance api contributes a major part in keeping our build fast.
When using the elasticsearch test cluster plugin we want to use (similar to the task avoidance API) a Gradle API to create domain objects lazy or only if required by the build.
Therefore we register test cluster by using the following syntax:
This registers a potential testCluster named `somecluster` and provides a provider instance, but doesn't create it yet nor configures it. This makes the gradle configuration phase more efficient by
Additional integration tests for a certain elasticsearch modules that are specific to certain cluster configuration can be declared in a separate so called `qa` subproject of your module.
The benefit of a dedicated project for these tests are:
-`qa` projects are dedicated two specific usecases and easier to maintain
- It keeps the specific test logic separated from the common test logic.
- You can run those tests in parallel to other projects of the build.
#### Using test fixtures
Sometimes we want to share test fixtures to setup the code under test across multiple projects. There are basically two ways doing so.
Ideally we would use the build-in [java-test-fixtures](https://docs.gradle.org/current/userguide/java_testing.html#sec:java_test_fixtures) gradle plugin.
This plugin relies on having a separate sourceSet for the test fixtures code.
In the elasticsearch codebase we have test fixtures and actual tests within the same sourceSet. Therefore we introduced the `elasticsearch.internal-test-artifact` plugin to provides another build artifact of your project based on the `test` sourceSet.
This artifact can be resolved by the consumer project as shown in the example below:
```
dependencies {
//add the test fixtures of `:providing-project` to testImplementation configuration.
This test artifact mechanism makes use of the concept of [component capabilities](https://docs.gradle.org/current/userguide/component_capabilities.html)
similar to how the gradle build-in `java-test-fixtures` plugin works.
`testArtifact` is a shortcut declared in the elasticsearch build. Alternatively you can declare the dependency via