Contributions from the community are essential in keeping Hibernate Search strong and successful.
This guide focuses on how to contribute back to Hibernate Search using GitHub pull requests.
All original contributions to Hibernate Search are licensed under the GNU Lesser General Public License (LGPL), version 2.1 or later, or, if another license is specified as governing the file or directory being modified, such other license. The LGPL text is included verbatim in the lgpl.txt file in the root directory of the repository.
All contributions are subject to the Developer Certificate of Origin (DCO). The DCO text is also included verbatim in the dco.txt file in the root directory of the repository.
If you want to see something fixed, but are not comfortable enough to dig into the codebase, you can help us by providing a well-documented bug report:
- Open a bug report on our JIRA instance. Make sure to provide enough information, in particular: the code you wrote, the expected result, the result you got instead, the version of your dependencies.
- Ideally (and this helps a lot), provide a self-contained test case. We provide test case templates for all Hibernate projects to help you get started: just fork this repository, build your test case and attach it as an archive to a JIRA issue.
If you are just getting started with Git, GitHub and/or contributing to Hibernate Search there are a few prerequisite steps:
- Make sure you have a Hibernate JIRA account
- Make sure you have a GitHub account
- Fork the Hibernate Search repository.
As discussed in the linked page, this also includes:
- Setting up your local git install
- Cloning your fork
Create a "topic" branch on which you will work. The convention is to name the branch using the JIRA issue key. If there is not already a JIRA issue covering the work you want to do, create one. Assuming you will be working from the master branch and working on the JIRA HSEARCH-123:
git checkout -b HSEARCH-123 master
The Hibernate family projects share the same style conventions, and we provide settings for some IDEs to help you follow these conventions. See:
If you built the project at least once (./mvnw clean install
),
you can very quickly check that you have respected the formatting rules by running Checkstyle:
./mvnw checkstyle:check -fn
See the README for details about how to build the project and about the structure of the source code.
If you need help, feel free to contact us, be it through comments on your JIRA ticket, emails on the mailing list, or directly though our chat: see here for more information.
-
Make commits of logical units.
-
Be sure to start the commit messages with the key of the JIRA issue you are working on. This is how JIRA will pick up the related commits and display them on the JIRA issue.
-
Avoid formatting changes to existing code as much as possible: they make the intent of your patch less clear.
-
Make sure you have added the necessary tests for your changes.
-
If relevant, make sure you have updated the documentation to match your changes.
-
Run all the tests to assure nothing else was accidentally broken:
./mvnw clean install
Prior to committing, if you want to pull in the latest upstream changes (highly appreciated by the way), please use rebasing rather than merging (see instructions below). Merging creates "merge commits" that really muck up the project timeline.
Add the original Hibernate Search repository as a remote repository called upstream:
git remote add upstream https://github.com/hibernate/hibernate-search.git
If you want to rebase your branch on top of the master branch, you can use the following git command:
git pull --rebase upstream master
- Push your changes to a topic branch in your fork of the repository.
- Initiate a pull request.
- Update the JIRA issue, using the "Link to pull request" button to include a link to the created pull request.
The project is split in several Maven modules:
backend
: The backends, i.e. the modules that provide integration to actual indexing services.elasticsearch
: A backend that connects to a remote Elasticsearch cluster.lucene
: A backend that uses an embedded (same JVM) Lucene instance.
build-config
: Code-related artifacts like checkstyle and forbiddenapis rules.distribution
: Builds the distribution package.documentation
: The project documentation.engine
: The Hibernate Search engine. This module handles most of the basic integration work (configuration properties, bean instantiation, ...), defines APIs common to every mapper/backend (the Search DSL in particular), and provides the "glue" between mappers and backends.integrationtest
: Integration tests for backends (Elasticsearch, Lucene) and mappers (Hibernate ORM), as well as any other technology Hibernate Search integrates with. Here are some notable sub-directories:performance
: performance tests.showcase/library
: a sample application using Hibernate Search in a Spring Boot environment.
mapper
: The mappers, i.e. the modules that expose APIs to index and search user entities, and do the work of converting between user entities and documents to be indexed.javabean
: An experimental (not published) mapper for Java Beans without Hibernate ORM. Mostly useful for tests of thepojo
module.orm
: A mapper for Hibernate ORM entities.pojo-base
: Contains base classes and APIs that are re-used in other POJO-based mapper.
reports
: Module built last, producing reports related to test coverage in particular.util
: Various modules containing util classes, both for runtime and for tests.
You will need JDK 11 or later.
The following command will build Hibernate Search, install it in your local Maven repository, and run unit tests and integration tests.
./mvnw clean install
Note: the produced JARs are compatible with Java 8 and later, regardless of the JDK used to build Hibernate Search.
The documentation is based on Asciidoctor. By default only the HTML output is enabled; to also generate the PDF output use:
./mvnw clean install -Pdocumentation-pdf
You can then find the freshly built documentation at the following location:
./documentation/target/dist/
To build the distribution bundle run:
./mvnw clean install -Pdocumentation-pdf,dist
The Elasticsearch integration tests run against one single version of Elasticsearch at a time,
launching an Elasticsearch server automatically on port 9200.
You may redefine the version to use by specifying the right profile and using the
test.elasticsearch.connection.version
property:
./mvnw clean install -Pelasticsearch-6.0 -Dtest.elasticsearch.connection.version=6.0.0
The following profiles are available:
elasticsearch-5.6
for 5.6.x and later 5.xelasticsearch-6.0
for 6.0.x to 6.2.xelasticsearch-6.3
for 6.3.xelasticsearch-6.4
for 6.4.x to 6.6.xelasticsearch-6.7
for 6.7.xelasticsearch-6.8
for 6.8 and later 6.xelasticsearch-7.0
for 7.0 to 7.2elasticsearch-7.3
for 7.3 to 7.6elasticsearch-7.7
for 7.7elasticsearch-7.8
for 7.8 to 7.9elasticsearch-7.10
for 7.10 (the default)elasticsearch-7.11
for 7.11+ (not open-source)
A list of available versions for test.elasticsearch.connection.version
can be found on
Maven Central.
Alternatively, you can prevent the build from launching an Elasticsearch server automatically
and run Elasticsearch-related tests against your own server using the
test.elasticsearch.connection.uris
property:
./mvnw clean install -Dtest.elasticsearch.connection.uris=http://localhost:9200
If you want to use HTTPS:
./mvnw clean install -Dtest.elasticsearch.connection.uris=https://localhost:9200
If you want to run tests against a different Elasticsearch version (6.x for instance), you will still have to select a profile among those listed above, and specify the version:
./mvnw clean install -Pelasticsearch-6.0 -Dtest.elasticsearch.connection.version=6.0.0 \
-Dtest.elasticsearch.connection.uris=http://localhost:9200
You may also use authentication:
./mvnw clean install -Dtest.elasticsearch.connection.uris=http://localhost:9200 \
-Dtest.elasticsearch.connection.username=ironman \
-Dtest.elasticsearch.connection.password=j@rV1s
Also, the elasticsearch integration tests can be executed against an Elasticsearch service on AWS. You will need to execute something along the lines of:
./mvnw clean install -Dtest.elasticsearch.connection.uris=http://<host:port> \
-Dtest.elasticsearch.connection.aws.signing.enabled=true \
-Dtest.elasticsearch.connection.aws.region=<Your AWS region ID> \
-Dtest.elasticsearch.connection.aws.credentials.type=static \
-Dtest.elasticsearch.connection.aws.credentials.access_key_id=<Your access key ID> \
-Dtest.elasticsearch.connection.aws.credentials.secret_access_key=<Your secret access key>
Or more simply, if your AWS credentials are already stored in ~/.aws/credentials
:
./mvnw clean install -Dtest.elasticsearch.connection.uris=http://<host:port> \
-Dtest.elasticsearch.connection.aws.signing.enabled=true \
-Dtest.elasticsearch.connection.aws.region=<Your AWS region ID>
When building Hibernate Search with new JDKs, you may want to run Elasticsearch with a different JDK than the one used by Maven. This can be done by setting a property (this will only work with the profiles for Elasticsearch 5 and above):
./mvnw clean install -Dtest.elasticsearch.run.java_home=/path/to/my/jdk
You can request static analysis and sanity checks with the jqassistant
profile.
Tests do not need to be run for these checks.
./mvnw clean install -Pjqassistant -DskipTests -DskipITs
To also check cyclic dependencies between packages, use -Djqassistant.groups=default,cycles
.
Cyclic dependency analysis is costly and may add significant overhead to the build:
at least 10 seconds, maybe one minute or more depending on your setup.
./mvnw clean install -Pjqassistant -DskipTests -DskipITs -Djqassistant.groups=default,cycles
You can also inspect the created Neo4j datastore after a build,
provided that build had the jqassistant
profile enabled:
./mvnw jqassistant:server -Pjqassistant
The Neo4j web UI will be accessible from http://localhost:7474/.
Some rules are not checked by Checkstyle, but will only be checked automatically when you submit a PR. You will spare yourself some back-and-forth by complying with them from the start.
Naming rules are the easiest. All classes/interfaces should be named according to this pattern:
[Abstract][<module-specific keyword>][<some meaningful name>][Impl]
- An
Abstract
prefix must be used for abstract classes. Exceptions are allowed for classes that don't implement any meaningful interface in which case the abstract class is assumed to represent both the interface and part of the implementation. and for marker classes (only private constructors). - An
Impl
suffix must only be used for non-abstract classes that are the only implementation of an interface defined in Hibernate Search, with the part of the name beforeImpl
being the name of the interface. - A module-specific keyword should be used whenever a type extends or implements a type from another module.
The exact keyword differs depending on the module, but is generally fairly obvious:
Elasticsearch
for the Elasticsearch backendLucene
for the Lucene backendPojo
for the Pojo mapperHibernateOrm
for the Hibernate ORM mapper- etc.
For example:
- If you add a non-abstract class in the Lucene backend that implements an interface
defined in the engine module, it should be named
Lucene<something>
- If you add a class in the Lucene backend that is the only implementation of an interface
that is also in the Lucene backend, it should be named
<name of the interface>Impl
. - If you add a class in the Lucene backend that is one of multiple implementations
of an interface that is also in the Lucene backend,
its name should not have an
Impl
suffix and should meaningfully describe what is specific to this implementation.
Architecture rules are a bit more complex; feel free to ignore them, submit your PR and let the reviewer guide you.
- Types whose package contains an "spi" component (
*.spi.*
) are considered SPI. - Types whose package contains an "impl" component (
*.impl.*
) are considered internal. - All other types are considered API.
- API types must not expose SPI or internal types, be it through inheritance, public or protected fields, or the return type or parameter type of public or protected methods.
- SPI types must not expose internal types, be it through inheritance, public or protected fields, or the return type or parameter type of public or protected methods.
- Types from a given module A must not depend on a internal type defined in another module B.
There are exceptions, for example if module B is purely internal (named
hibernate-search-*-internal-*
), likehibernate-search-util-interal-common
.