Skip to content

Commit 073604c

Browse files
authored
chore(build): update build-plugin (#4)
2 parents b7b9afe + 8283e75 commit 073604c

55 files changed

Lines changed: 1625 additions & 645 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,6 @@ out/
3232

3333
# Mac thumbnail db
3434
.DS_Store
35+
36+
# Signing
37+
.signing/

build-plugin/README.md

Lines changed: 87 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,116 @@
11
# Build plugins
22

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.
55

66
## Background
77

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`.
1211

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`.
1514

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
1816

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
2020

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:
2422

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`)
2635

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
3537

36-
## Add new build plugin
38+
In any module’s `build.gradle.kts`:
3739

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+
```
3956

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
4158

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:
4660

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`
4863

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:
5065

5166
```
52-
plugins {
53-
id(ThunderbirdPlugins.xyz)
67+
codeCoverage {
68+
disabled.set(false)
69+
lineCoverage.set(80)
70+
branchCoverage.set(70)
5471
}
5572
```
5673

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:
5996

6097
```
61-
plugins {
62-
id("thunderbird.xyz")
63-
}
98+
includeBuild("build-plugin")
6499
```
65100

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+
66114
## Acknowledgments
67115

68116
- [Herding Elephants | Square Corner Blog](https://developer.squareup.com/blog/herding-elephants/)

build-plugin/build.gradle.kts

Lines changed: 0 additions & 32 deletions
This file was deleted.

build-plugin/gradle.properties

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
kotlin.code.style=official
2+
org.gradle.caching=true
3+
org.gradle.parallel=true
4+
org.gradle.configureondemand=true
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
plugins {
2+
`kotlin-dsl`
3+
}
4+
5+
group = "net.thunderbird.gradle.plugin"
6+
7+
dependencies {
8+
implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location))
9+
10+
compileOnly(plugin(libs.plugins.android.application))
11+
12+
compileOnly(plugin(libs.plugins.kotlin.multiplatform))
13+
compileOnly(plugin(libs.plugins.kotlin.serialization))
14+
15+
compileOnly(plugin(libs.plugins.compose.compiler))
16+
compileOnly(plugin(libs.plugins.compose.multiplatform))
17+
compileOnly(plugin(libs.plugins.compose.hot.reload))
18+
19+
implementation(plugin(libs.plugins.dependency.check))
20+
21+
implementation(plugin(libs.plugins.maven.publish))
22+
23+
implementation(plugin(libs.plugins.kover))
24+
implementation(plugin(libs.plugins.detekt))
25+
implementation(plugin(libs.plugins.spotless))
26+
27+
compileOnly(libs.kotlinx.datetime)
28+
}
29+
30+
gradlePlugin {
31+
plugins {
32+
register("AppKmpCompose") {
33+
id = "net.thunderbird.gradle.plugin.app.kmp.compose"
34+
implementationClass = "net.thunderbird.gradle.plugin.app.kmp.compose.AppKmpComposePlugin"
35+
}
36+
register("LibraryKmp") {
37+
id = "net.thunderbird.gradle.plugin.library.kmp"
38+
implementationClass = "net.thunderbird.gradle.plugin.library.kmp.LibraryKmpPlugin"
39+
}
40+
register("LibraryKmpCompose") {
41+
id = "net.thunderbird.gradle.plugin.library.kmp.compose"
42+
implementationClass = "net.thunderbird.gradle.plugin.library.kmp.compose.LibraryKmpComposePlugin"
43+
}
44+
45+
register("DependencyCheck") {
46+
id = "net.thunderbird.gradle.plugin.dependency.check"
47+
implementationClass = "net.thunderbird.gradle.plugin.dependency.check.DependencyCheckPlugin"
48+
}
49+
50+
register("Publishing") {
51+
id = "net.thunderbird.gradle.plugin.publishing"
52+
implementationClass = "net.thunderbird.gradle.plugin.publishing.PublishingPlugin"
53+
}
54+
55+
register("QualityCodeCoverage") {
56+
id = "net.thunderbird.gradle.plugin.quality.coverage"
57+
implementationClass = "net.thunderbird.gradle.plugin.quality.coverage.CodeCoveragePlugin"
58+
}
59+
register("QualityDetekt") {
60+
id = "net.thunderbird.gradle.plugin.quality.detekt"
61+
implementationClass = "net.thunderbird.gradle.plugin.quality.detekt.DetektPlugin"
62+
}
63+
register("QualitySpotless") {
64+
id = "net.thunderbird.gradle.plugin.quality.spotless"
65+
implementationClass = "net.thunderbird.gradle.plugin.quality.spotless.SpotlessPlugin"
66+
}
67+
68+
register("Versioning") {
69+
id = "net.thunderbird.gradle.plugin.versioning"
70+
implementationClass = "net.thunderbird.gradle.plugin.versioning.VersioningPlugin"
71+
}
72+
}
73+
}
74+
75+
private fun plugin(provider: Provider<PluginDependency>) = with(provider.get()) {
76+
"$pluginId:$pluginId.gradle.plugin:$version"
77+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package net.thunderbird.gradle.plugin
2+
3+
import org.gradle.api.plugins.ExtensionAware
4+
import org.gradle.kotlin.dsl.getByType
5+
import org.jetbrains.compose.ComposePlugin.Dependencies
6+
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
7+
8+
internal val KotlinMultiplatformExtension.compose: Dependencies
9+
get() = (this as ExtensionAware).extensions.getByType<Dependencies>()
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package net.thunderbird.gradle.plugin
2+
3+
import org.gradle.accessors.dm.LibrariesForLibs
4+
import org.gradle.api.Project
5+
import org.gradle.kotlin.dsl.getByName
6+
7+
val Project.libs
8+
get(): LibrariesForLibs = extensions.getByName<LibrariesForLibs>("libs")
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package net.thunderbird.gradle.plugin
2+
3+
import org.gradle.api.JavaVersion
4+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
5+
6+
object ProjectConfig {
7+
8+
const val group = "net.thunderbird"
9+
10+
object Android {
11+
const val sdkMin = 21
12+
13+
// Only needed for application
14+
const val sdkTarget = 35
15+
16+
const val sdkCompile = 36
17+
}
18+
19+
object Compiler {
20+
val javaCompatibility = JavaVersion.VERSION_11
21+
val jvmTarget = JvmTarget.JVM_11
22+
}
23+
24+
object Publishing {
25+
const val year = "2025"
26+
const val url = "https://github.com/thunderbird/thunderbird-mobile-components"
27+
28+
const val licenseName = "MPL-2.0"
29+
const val licenseUrl = "https://www.mozilla.org/en-US/MPL/2.0/"
30+
const val licenseDistribution = "https://www.mozilla.org/en-US/MPL/2.0/"
31+
32+
const val developerId = "thunderbird"
33+
const val developerName = "Thunderbird Mobile Team"
34+
const val developerEmail = "mobile@thunderbird.net"
35+
36+
const val scmUrl = "https://github.com/thunderbird/thunderbird-mobile-components"
37+
const val scmConnection = "scm:git:git://github.com/thunderbird/thunderbird-mobile-components.git"
38+
const val scmDeveloperConnection = "scm:git:ssh://git@github.com/thunderbird/thunderbird-mobile-components.git"
39+
}
40+
}

0 commit comments

Comments
 (0)