gradle-project-setup-howto

Introduction: How to structure a growing Gradle project with smart dependency management?
More: Author   ReportBugs   
Tags:

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.

Feature Plugins

Each feature plugin configures one aspect of building the software – like compiling code or testing code.

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.

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.

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

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.

More questions or points you would like to discuss? Please open an issue.

Apps
About Me
GitHub: Trinea
Facebook: Dev Tools