|
1 | 1 | # Build plugins |
2 | 2 |
|
3 | | -The `build-plugin` folder defines Gradle build plugins, used as single source of truth for the project configuration. |
4 | | -This helps to avoid duplicated build script setups and provides a central location for all common build logic. |
| 3 | +The `build-plugin` project provides a set of Gradle plugins that act as the single source of truth for |
| 4 | +project-wide build configuration. This avoids duplicated build script setups and centralizes common build logic. |
5 | 5 |
|
6 | 6 | ## Background |
7 | 7 |
|
8 | | -We use Gradle's |
9 | | -[sharing build logic in a multi-repo setup](https://docs.gradle.org/current/samples/sample_publishing_convention_plugins.html) |
10 | | -to create common configuration. It allows usage of `xyz.gradle.kts` files, that are then automatically converted to |
11 | | -Gradle Plugins. |
| 8 | +We use an included build to host our build logic as real Gradle plugins (written in Kotlin), not as legacy |
| 9 | +`*.gradle.kts` convention scripts. The included build is located at `build-plugin/plugin` and registers plugins |
| 10 | +via the Gradle `gradlePlugin` block in `build-plugin/plugin/build.gradle.kts`. |
12 | 11 |
|
13 | | -The `build-plugin` is used as included build in the root `settings.gradle.kts` and provides all |
14 | | -included `xyz.gradle.kts` as plugins under their `xyz` name to the whole project. |
| 12 | +You apply these plugins in modules using their fully-qualified plugin IDs. Each plugin focuses on a single |
| 13 | +responsibility; one-off configuration should stay in the module’s own `build.gradle.kts`. |
15 | 14 |
|
16 | | -The plugins should try to accomplish single responsibility and leave one-off configuration to the |
17 | | -module's `build.gradle.kts`. |
| 15 | +## Available plugins |
18 | 16 |
|
19 | | -## Convention plugins |
| 17 | +- `net.thunderbird.gradle.plugin.app.kmp.compose` — Configures common options for Kotlin Multiplatform Compose apps |
| 18 | +- `net.thunderbird.gradle.plugin.library.kmp` — Configures common options for Kotlin Multiplatform libraries |
| 19 | +- `net.thunderbird.gradle.plugin.library.kmp.compose` — Configures common options for KMP Compose libraries |
20 | 20 |
|
21 | | -- `thunderbird.app.kmp.compose` - Configures common options for Kotlin Multiplatform Compose applications |
22 | | -- `thunderbird.library.kmp` - Configures common options for Kotlin Multiplatform libraries |
23 | | -- `thunderbird.library.kmp.compose` - Configures common options for Kotlin Multiplatform Compose libraries |
| 21 | +Supportive/quality and tooling plugins: |
24 | 22 |
|
25 | | -## Supportive plugins |
| 23 | +- `net.thunderbird.gradle.plugin.dependency.check` — [Gradle Versions Plugin](https://github.com/ben-manes/gradle-versions-plugin) |
| 24 | + - Run `./gradlew dependencyUpdates` to generate a dependency update report |
| 25 | +- `net.thunderbird.gradle.plugin.quality.detekt` — [Detekt](https://detekt.dev/) static analysis for Kotlin |
| 26 | + - Run `./gradlew detekt` to analyze, and `./gradlew detektBaseline` if you can’t fix issues yet |
| 27 | +- `net.thunderbird.gradle.plugin.quality.spotless` — [Spotless](https://github.com/diffplug/spotless) with |
| 28 | + [Ktlint](https://pinterest.github.io/ktlint/) for formatting |
| 29 | + - Run `./gradlew spotlessCheck` to verify and `./gradlew spotlessApply` to format |
| 30 | +- `net.thunderbird.gradle.plugin.quality.coverage` — Configures [Kover](https://github.com/Kotlin/kotlinx-kover) |
| 31 | + code coverage with sensible defaults |
| 32 | + - Common tasks: `./gradlew koverHtmlReport`, `./gradlew koverXmlReport`, `./gradlew koverVerify` |
| 33 | +- `net.thunderbird.gradle.plugin.publishing` — Configures publishing (Maven coordinates, POM metadata, and common |
| 34 | + repositories like `mavenLocal()` and a local build repo under `build/maven-repo`) |
26 | 35 |
|
27 | | -- `thunderbird.dependency.check` - [Gradle Versions: Gradle plugin to discover dependency updates](https://github.com/ben-manes/gradle-versions-plugin) |
28 | | - - Use `./gradlew dependencyUpdates` to generate a dependency update report |
29 | | -- `thunderbird.quality.detekt` - [Detekt - Static code analysis for Kotlin](https://detekt.dev/) |
30 | | - - Use `./gradlew detekt` to check for any issue and `./gradlew detektBaseline` in case you can't fix the reported |
31 | | - issue. |
32 | | -- `thunderbird.quality.spotless` - [Spotless - Code formatter](https://github.com/diffplug/spotless) |
33 | | - with [Ktlint - Kotlin linter and formatter](https://pinterest.github.io/ktlint/) |
34 | | - - Use `./gradlew spotlessCheck` to check for any issue and `./gradlew spotlessApply` to format your code |
| 36 | +### Applying a plugin |
35 | 37 |
|
36 | | -## Add new build plugin |
| 38 | +In any module’s `build.gradle.kts`: |
37 | 39 |
|
38 | | -Create a `thunderbird.xyz.gradle.kts` file, while `xyz` describes the new plugin. |
| 40 | +``` |
| 41 | +plugins { |
| 42 | + id("net.thunderbird.gradle.plugin.library.kmp") |
| 43 | + // or |
| 44 | + id("net.thunderbird.gradle.plugin.app.kmp.compose") |
| 45 | +} |
| 46 | +``` |
| 47 | + |
| 48 | +These IDs also work in the root build script when a plugin is designed to be applied at the root (for example, |
| 49 | +`publishing` or top-level quality configurations): |
| 50 | + |
| 51 | +``` |
| 52 | +plugins { |
| 53 | + id("net.thunderbird.gradle.plugin.publishing") |
| 54 | +} |
| 55 | +``` |
39 | 56 |
|
40 | | -If you need to access dependencies that are not yet defined in `build-plugin/build.gradle.kts` you have to: |
| 57 | +### Code coverage configuration |
41 | 58 |
|
42 | | -1. Add the dependency to the version catalog `gradle/libs.versions.toml` |
43 | | -2. Then add it to `build-plugin/build.gradle.kts`. |
44 | | - 1. In case of a plugin dependency use `implementation(plugin(libs.plugins.YOUR_PLUGIN_DEPENDENCY))`. |
45 | | - 2. Otherwise `implementation(libs.YOUR_DEPENDENCY))`. |
| 59 | +When using `net.thunderbird.gradle.plugin.quality.coverage` you can tune or disable coverage checks: |
46 | 60 |
|
47 | | -When done, add the plugin to `build-plugin/src/main/kotlin/ThunderbirdPlugins.kt` |
| 61 | +- Disable via Gradle property: `-PcodeCoverageDisabled=true` |
| 62 | +- Disable via environment variable: `CODE_COVERAGE_DISABLED=true` |
48 | 63 |
|
49 | | -Then apply the plugin to any subproject it should be used with: |
| 64 | +Configure thresholds in a module’s `build.gradle.kts` using the `codeCoverage` extension: |
50 | 65 |
|
51 | 66 | ``` |
52 | | -plugins { |
53 | | - id(ThunderbirdPlugins.xyz) |
| 67 | +codeCoverage { |
| 68 | + disabled.set(false) |
| 69 | + lineCoverage.set(80) |
| 70 | + branchCoverage.set(70) |
54 | 71 | } |
55 | 72 | ``` |
56 | 73 |
|
57 | | -If the plugin is meant for the root `build.gradle.kts`, you can't use `ThunderbirdPlugins`, as it's not available to |
58 | | -the `plugins` block. Instead use: |
| 74 | +Reports and verification are provided by Kover (JaCoCo backend is pinned by the plugin). |
| 75 | + |
| 76 | +### Publishing configuration |
| 77 | + |
| 78 | +The `net.thunderbird.gradle.plugin.publishing` plugin: |
| 79 | + |
| 80 | +- Applies the Vanniktech Maven Publish plugin |
| 81 | +- Sets Maven coordinates from the project and configures POM metadata |
| 82 | +- Adds local repositories: `mavenLocal()` and `${rootProject}/build/maven-repo` |
| 83 | +- Configures publishing to Maven Central and signs all publications |
| 84 | + |
| 85 | +Signing properties can be supplied from a file at `${rootProject}/.signing/signing.properties` with keys: |
| 86 | + |
| 87 | +- `signing.keyId` |
| 88 | +- `signing.password` |
| 89 | +- `signing.secretKeyRingFile` |
| 90 | + |
| 91 | +Alternatively, you may provide equivalent Gradle properties via other supported mechanisms. |
| 92 | + |
| 93 | +### Included build wiring |
| 94 | + |
| 95 | +These plugins are provided by an included build. The root `settings.gradle.kts` contains: |
59 | 96 |
|
60 | 97 | ``` |
61 | | -plugins { |
62 | | - id("thunderbird.xyz") |
63 | | -} |
| 98 | +includeBuild("build-plugin") |
64 | 99 | ``` |
65 | 100 |
|
| 101 | +## Creating a new build plugin |
| 102 | + |
| 103 | +1. Create a Kotlin plugin class under `build-plugin/plugin/src/main/kotlin/...`, implementing `Plugin<Project>`. |
| 104 | +2. Register it in `build-plugin/plugin/build.gradle.kts` inside the `gradlePlugin { plugins { ... } }` block with a |
| 105 | + unique ID and the `implementationClass` pointing to your class. |
| 106 | +3. Dependencies: |
| 107 | + - Add versions and aliases to the version catalog `gradle/libs.versions.toml` (if not present yet). |
| 108 | + - Add the dependency to `build-plugin/plugin/build.gradle.kts`. |
| 109 | + - Plugin dependency: `implementation(plugin(libs.plugins.YOUR_PLUGIN))` |
| 110 | + - Library dependency: `implementation(libs.YOUR_LIBRARY)` |
| 111 | + |
| 112 | +After that, apply your plugin by its ID in any module’s `plugins` block. |
| 113 | + |
66 | 114 | ## Acknowledgments |
67 | 115 |
|
68 | 116 | - [Herding Elephants | Square Corner Blog](https://developer.squareup.com/blog/herding-elephants/) |
|
0 commit comments