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:
- 𧩠Java Module System
- 𦩠Kotlin
- π€ Android
- π Java and Spring Boot
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.
βββ 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
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
}
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 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
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 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 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 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.
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.
- 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)
- 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.
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.