gradle-project-setup-howto
This repo contains a Gradle project structure with:
- Centralized and maintainable build configuration and custom build logic
- No dependency hell through smart dependency management with dependency rules and analysis
The main
branch contains everything for a traditional Java project.
The structure though, is good for any kind of project you may build with Gradle
(Kotlin, Groovy, Scala, ...).
[!NOTE] There are adjustments on other branches of this repo that show how the setup can be varied:
This is following similar patterns as idiomatic-gradle but is closer to a full setup that also takes the aspect of continuously changing dependencies into account.
Project Overview
Folder structure
├── settings.gradle.kts - Entry point file for Gradle to work with the project struture
├── $module-name - Each Module of the software has a folder
│ ├── src - Production code and test code
│ └── build.gradle.kts - Defines the type of the Module and its dependencies
├── gradle - Contains the build configuraton
│ ├── version.txt - Defines the version of the software all Modules share
│ ├── jdk-version.txt - Defines Java version used in the project
│ ├── libs.versions.toml - Version catalog defines versions of 3rd party modules
│ ├── versions/build... - 3rd party version restrictions if needed
│ ├── aggregation/build... - Aggregated reports for the whole project
│ ├── plugins/build... - Define which 3rd party plugins are used and their versions
│ │ └── src/main/kotlin - Individual plugin configurations (aka Convention Plugins)
│ └── wrapper - Define Gradle version used via Gradle Wrapper
├── gradle.properties - Gradle startup parameters and global switches
├── build.gradle.kts - Use plugins for checks and auto-formating on the whole project
└── .github - Integrate with GitHub Actions CI system
The $module-name/build.gradle.kts files
Select a Component Type by using the corresponding convention plugin and define the dependencies of the module. For example:
plugins {
id("org.example.gradle.component.library") // This is a 'library'
id("org.example.gradle.feature.publish") // Build feature only in this 'library' Module
}
dependencies {
api(projects.coruscant) // Depends on another Module of our project
implementation(libs.guava) // Depends on a 3rd party Module
}
The Convention Plugins
Convention plugins are used to configure each aspect of the build centrally. To keep it structured, we put them into four categories: Base, Feature, Check, Report. Below you find all plugins listed. For more details, inspect the corresponding plugin files. Understanding Gradle videos that cover related topics are linked below each plugin file.
Base Plugins
Base plugins need to be used in all Modules to establish a certain foundation for the setup. For example, the same dependency management configuration should be applied everywhere to consistently use the same 3rd party libraries everywhere.
- org.example.gradle.base.identity.gradle.kts
- org.example.gradle.base.lifecycle.gradle.kts
- org.example.gradle.base.lifecycle.root.gradle.kts
- org.example.gradle.base.dependency-rules.gradle.kts
Feature Plugins
Each feature plugin configures one aspect of building the software – like compiling code or testing code.
- org.example.gradle.feature.repositories.settings.gradle.kts
- org.example.gradle.feature.project-structure.settings.gradle.kts
- org.example.gradle.feature.compile-java.gradle.kts
- org.example.gradle.feature.javadoc.gradle.kts
- org.example.gradle.feature.test.gradle.kts
- org.example.gradle.feature.test-end-to-end.gradle.kts
- org.example.gradle.feature.test-fixtures.gradle.kts
- org.example.gradle.feature.war.gradle.kts
- org.example.gradle.feature.checksum.gradle.kts
- org.example.gradle.feature.publish.gradle.kts
- org.example.gradle.feature.use-all-catalog-versions.gradle.kts
- org.example.gradle.feature.build-cache.settings.gradle.kts
Report Plugins
Report plugins add reporting functionality to discover potential issues with the software or the build setup. They may generate data that is picked up and displayed by external tools like Develocity or Dependency Track. More reporting tools may be integrated in this category. Report plugins are not necessarily needed to build a working software.
- org.example.gradle.report.code-coverage.gradle.kts
- org.example.gradle.report.plugin-analysis.gradle.kts
- org.example.gradle.report.sbom.gradle.kts
- org.example.gradle.report.develocity.settings.gradle.kts
Check Plugins
Check plugins help with keeping the software maintainable over time. They check things like the dependency setup or code formatting. More style checkers or static code analysis tools could be added in this category. Check plugins are not necessarily needed to build a working software.
- org.example.gradle.check.dependencies.gradle.kts
- org.example.gradle.check.format-gradle.gradle.kts
- org.example.gradle.check.format-gradle.root.gradle.kts
- org.example.gradle.check.format-java.gradle.kts
Component Plugins
Component plugins combine plugins from all categories above to define Component Types that are then used in the build.gradle.kts
files of the individual Modules of our software.
Testing Plugins
The Gradle TestKit can be used to test plugins. This can be helpful to enforce a certain structure, e.g. by testing if each plugin works on its own. And if you add custom tasks and advanced logic, you can add tests for that. As example, this project contains one test class: ConventionPluginTest.kt
There is also a help task that you can use to get a diagram of the convention plugins defined in the project:
./gradlew :aggregation:analysePluginApplicationOrder
The task generates a PlantUML file that you can render, for example, with the PlantUML IntelliJ plugin.
Continuously build and report using GitHub Actions and Dependabot
- build.yaml Configure GitHub to run builds and produce reports (👉inspect). Integrates with:
- Develocity Build Scans (👉inspect)
- Gradle Remote Build Cache
- Reposilite (👉inspect)
- Dependency Track (👉inspect login: guest/guest)
- dependabot.yml Configure Dependabot to automatically get version updates (👉inspect)
Notes
- If you have a question, please ask in an issue.
- The concrete things done in all places (custom tasks, components used in dependencies, additional plugins applied, etc.) are just examples. If you, for example, need to use additional Gradle plugins you can add these in the corresponding place, keeping the suggested structure.
- There was a different version of this repository I initially published in 2022. The setup was more complex by splitting the Gradle configuration over move folders which required more boilerplate. After using a setup like his in several projects, I felt that the setup was overly complex without adding much value. I ended up striping it down to what this repository is now. The older version is still accessible on the 2022_java branch.
FAQ
List of questions asked in issues so far.
- Why is the :app project special?
- Dependency Analysis: How to ignore dependencies added by plugins?
- Dependency Analysis: How to remove dependencies added by plugins?
- How many convention plugins should be used?
- How to customize the wrapper task?
- What are good practices when publishing libraries (API consistency, multiple variants, transitives)?
- Kotlin branch: Why is there a special handling of kotlin-stdlib?
- Kotlin branch: How to avoid the 'The Kotlin Gradle plugin was loaded multiple times' error?
- Spring branch: Why does the example not use the Spring Boot Dependency Management plugin?
More questions or points you would like to discuss? Please open an issue.