BGW makes heavy use of “advanced” Gradle features to abstract away most build logic. This is a guide to the Gradle features and custom extension used (and how to modify them).
Build logic is extracted to convention plugins. They are located in buildSrc/src/main/kotlin
and are compiled from
the *.gradle.kts
files contained there. These follow the syntax for normal Gradle build files, but are compiled into
Gradle plugins behind the scenes. A convention plugin named tools.aqua.xyz.gradle.kts
can be applied by using
plugins {
id("tools.aqua.xyz")
}
Further information on convention plugins can be found in the Gradle documentation.
Each Plugin is designed to contain common configuration for one project facette.
The base conventions apply three plugins:
- Gradle Task Tree helps with debugging the build performed by Gradle (e.g., missing task dependencies).
- Gradle Version Plugin can be used to check dependencies for
updates. Since plugins are declared via
buildSrc
, it can unfortunately not detect plugin updates. - Spotless is used for enforcing style and license headers on the Gradle build
files. The license header templates are located in the
contrib
folder.
It should be “inherited“ by all other conventions.
The Kotlin conventions handle the setup of the Kotlin compiler, documentation generation, testing, and code quality
enforcement. Style and license headers of Kotlin source files are again enforced
via Spotless. Additionally, Detekt is configured to
perform additional quality checks on Kotlin files, but will not fail the build on violations. The Detekt configuration
(with some rationales) is located in contrib/detekt-rules.yml
.
The publish conventions handle publication of artifacts via Maven Central. Most of the process is automated, but each
module must provide a name and description for the generated POM file. This is done using the (custom) MavenMetadata
extension:
mavenMetadata {
name.set("BoardGameWork Thing")
description.set("A thing for working board games.")
}
The extension also enforces signing as soon as a publication task (including publishToMavenLocal
) is included in the
build process. Each developer must generate a GPG key for signing and register the ID in their Gradle system
properties file. See the Gradle documentation for
details.
The executable conventions should be applied to every module that contains a main class. They enable the Kotlin and
publishing configurations as well as the
application plugin. Each module using these
conventions must set an appropriate main class. See the bgw-examples
modules for examples.
The library conventions should be applied to every module that is intended to be reused. They enable the Kotlin and
publishing configurations as well as the
Java library plugin. Each module using this
convention must take care to differentiate api
and implementation
dependencies. This convention can be combined with
the executable convention for programs with a defined API. See the bgw-gui
module for an example.
The Spring Boot + Vaadin conventions should be applied to each module that uses these frameworks. They set up all
relevant plugins and BOMs and include some required dependencies. They enable the Kotlin and publishing configurations.
See the bgw-net/bgw-net-server
module for an example.
The root conventions must only be applied to the root project and set up plugins that must be applied there. This
includes code coverage (to enable data aggregation across subprojects), style enforcement
via Spotless for the buildSrc
, and automatic version generation using the
Gradle Git Versioning Plugin.
The latter generates version numbers from the current Git state and requires a non-sparse Git checkout to work correctly. The versioning rules are:
- If the HEAD points to a tag beginning with
v
, the remainder of the tag is used as a version (i.e., a release). - If the branch is
main
, the version is the last release, plus agit describe
-style specified, as aSNAPSHOT
. - If the branch is not
main
, the version is the last release, plus the branch name, plus agit describe
-style specified, as aSNAPSHOT
. - Otherwise, the version of last resort is
0.0.0-SNAPSHOT
and a warning is emitted.
The Jekyll conventions are designed for generated documentation sites and mostly emulate the build process provided by
GitHub Pages. They provide the configuration includedKDoc
for KDoc JARs that are to be included in the generated page.
For example, the dependency
includedKDoc(project(":bgw-thing", "kdoc"))
will take the artifact associated with the configuration kdoc
from the project bgw-thing
and unpack it in the
directory bgw-thing
relative to the site root. The kdoc
configuration is provided by every project using
the kotlin-conventions
.
The Jekyll support is custom developed and uses a Jekyll Docker container. If Docker is not running, the jekyllBuild
task defined by this convention will fail. Additionally, a pure-Java server is provided to test the generated site
locally. See bgw-docs
for an example.
Some custom build code is provided in buildSrc/src/main/kotlin/tools/aqua
. This includes some shorthand notation used
inside the conventions, the MavenMetadata
extension, and the Jekyll-related tasks. They contain explanatory KDoc
comments. Note that all code provided there is visible from all build scripts, both in buildSrc
and regular modules.
The BGW project utilizes version catalogs provided by the gradle/libs.versions.toml
file. All dependencies used by
BGW projects should be defined there and included into projects using Gradle's type-safe accessor syntax. See any
project or convention for examples.
The file uses some shared version declarations in the [versions]
block. These are required for versions shared by
multiple dependencies (e.g., Kotlin) and versions of non-Java-dependencies (i.e., the Jekyll Docker image). Depencencies
themselves are declared in the [libraries]
block. Since Gradle plugins are applies via buildSrc
and are therefore *
regular* dependencies of that project, they are declared here. Their aliases are prefixed by gradle-
. Bundles are used
to group some common dependencies, while plugin aliases cannot be used in combination with buildSrc
-applied plugins.
The Gradle documentation should be consulted for further information on catalogs and the TOML syntax.
As mentioned above, consistent styling is enforced via Spotless. A consistent
style can therefore be enforced by executing the spotlessApply
task on the project. Note that Spotless is somewhat
memory-hungry, Gradle is therefore configured to use up to 1GiB of heap memory to avoid crashes. Since the Kotlin style
is applied using Ktfmt, developers may want to configure their IDEs to use
that style, but should still reformat their code.
Additionally, Detekt is used to flag code smells. Developers should consult the reports (and CLI
output) created by detekt
and attempt to rectify the issues. Finally, the Kotlin compiler is instructed to treat
warnings as errors.