Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #353 from jmfayard/draft-kodein-di
- New `DpendencyGroup` base API for dependency notations - Documentation for it - Dependency notations for Spring, Http4k, Kodein DI
- Loading branch information
Showing
19 changed files
with
2,236 additions
and
85 deletions.
There are no files selected for viewing
62 changes: 56 additions & 6 deletions
62
docs/contributing/submitting-prs/dependency-notations-updates.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,60 @@ | ||
# Submitting dependency notations updates | ||
# Submitting dependency notations | ||
|
||
Thanks for considering an update to the built-in dependency notations in refreshVersions! | ||
We want to provide dependency notations for more popular libraries. | ||
|
||
However, we are in the process of refactoring the way we define dependency notations in refreshVersions, | ||
so it's less overhead for both you and us, and less error-prone to do overall (especially regarding backwards and forward compatibility). | ||
Want to contribute some? | ||
|
||
That means that **we're unlikely to accept any submission** of dependency notation updates **for now**. | ||
Here is what a dependency notation should look like: | ||
|
||
To be informed when that refactoring is complete, you can subscribe to this issue: {{link.issues}}/275 | ||
```kotlin | ||
@file:Suppress("PackageDirectoryMismatch", "SpellCheckingInspection", "unused") // 1 | ||
|
||
import de.fayard.refreshVersions.core.internal.DependencyGroup | ||
import org.gradle.api.Incubating | ||
import org.gradle.kotlin.dsl.IsNotADependency | ||
|
||
/** // 2 | ||
* painless Kotlin dependency injection | ||
* | ||
* - [Official website here](https://kodein.org/di/) | ||
* - GitHub page: [Kodein-Framework/Kodein-DI](https://github.com/Kodein-Framework/Kodein-DI) | ||
* - [GitHub Releases here](https://github.com/Kodein-Framework/Kodein-DI/releases) | ||
*/ | ||
@Incubating | ||
object Kodein: IsNotADependency { // 3 | ||
|
||
val di = DI // 4 | ||
|
||
object DI : DependencyGroup( // 5 | ||
group = "org.kodein.di", // 6 | ||
usePlatformConstraints = true, // 7 | ||
rawRule = """ | ||
org.kodein.di:kodein-di(-*) | ||
^^^^^^^^^ | ||
""".trimIndent() // 8 | ||
) { | ||
val bom by module("kodein-bom", isBom = true) // 9 | ||
val js by module("kodein-di-js") // 10 | ||
val androidx by module("kodein-di-framework-android-x") | ||
} | ||
} | ||
``` | ||
|
||
Here is what you need to know: | ||
|
||
1. We use on purpose no package - annd suppress the corresponding warning - so that the user doesn't have to import the dependency notation | ||
2. We provide a KDoc with a description of what the library does and link to GitHub and the documentation | ||
3. We tag classes with `IsNotADependency` so that the IDE shows a warning if the user tries to do `implementation(Kodein)` | ||
4. We support Gradle build scripts in both Kotlin and Groovy. `Kodein.DI` works in Kotlin but not in Groovy. That's why we have the property `Kotlin.di` who works in both. | ||
5. We use the base class `DependencyGroup` to define a group of dependency notations. | ||
6. The maven group that will be used for all the modules of this `DependencyGroup`. | ||
7. If the library provides a Bill of Materials `BoM` of another kind of platform constraints, we set `usePlatformConstraints = true`. | ||
8. All dependency notations with a name like `org.kodein.di:kodein-di(-*)` will use the same version `version.kodein.di` because we defined an artifact rule. To learn more about [refreshVersions rules, have a look here](thttps://github.com/jmfayard/refreshVersions) | ||
9. DependencyGroup has firt class support for `BoM`s via the `isBom = true` parameter. It switches the boolean `usePlatformConstraints = true` and does various checks. | ||
10. A module is defined via the `by module("module.name")` syntax. | ||
|
||
Three more things before you start coding: | ||
|
||
- Look at [`Http4K`, `Spring` or `Kodein`](https://github.com/jmfayard/refreshVersions/tree/main/plugins/dependencies/src/main/kotlin/dependencies) for inspiration. | ||
- **Try to not forget any artifact!**. One of the best way to do that is to open an issue in the project of the library for which you contribute dependency notations. | ||
- **Run the unit tests!**. There are multiple checks that are done to prevent the most common mistakes. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
77 changes: 77 additions & 0 deletions
77
plugins/core/src/main/kotlin/de/fayard/refreshVersions/core/internal/DependencyGroup.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package de.fayard.refreshVersions.core.internal | ||
|
||
import org.gradle.kotlin.dsl.IsNotADependency | ||
import kotlin.reflect.KProperty | ||
|
||
@InternalRefreshVersionsApi | ||
open class DependencyGroup( | ||
val group: String, | ||
rawRule: String? = null, | ||
var usePlatformConstraints: Boolean = false | ||
) : IsNotADependency { | ||
|
||
val rule: ArtifactVersionKeyRule? = rawRule?.let { | ||
val lines = it.lines() | ||
assert(lines.size == 2) { | ||
"2 lines were expected, but ${lines.size} were found: $it" | ||
} | ||
ArtifactVersionKeyRule( | ||
artifactPattern = lines.first(), | ||
versionKeyPattern = lines.last() | ||
) | ||
} | ||
|
||
|
||
companion object { | ||
private val ALL = mutableListOf<DependencyGroup>() | ||
val ALL_RULES: List<ArtifactVersionKeyRule> | ||
get() = ALL.mapNotNull { it.rule } | ||
|
||
private val isRunningTests: Boolean by lazy { | ||
try { | ||
Class.forName("org.junit.jupiter.api.AssertEquals") | ||
true | ||
} catch (e: ClassNotFoundException) { | ||
false | ||
} | ||
} | ||
} | ||
|
||
init { | ||
assert(group.isNotBlank()) { "Group shall not be blank" } | ||
ALL.add(this) | ||
} | ||
|
||
fun module(module: String, isBom: Boolean = false): Module { | ||
assert(module.trimStart() == module) { "module=[$module] has superfluous leading whitespace" } | ||
assert(module.trimEnd() == module) { "module=[$module] has superfluous trailing whitespace" } | ||
assert(module.contains(":").not()) { "module=[$module] is invalid" } | ||
return Module( | ||
name = "$group:$module" + if (usePlatformConstraints && isBom.not()) "" else ":_", | ||
isBom = isBom | ||
) | ||
} | ||
|
||
private var haveDependencyNotationsBeenUsed = false | ||
|
||
operator fun Module.getValue(thisRef: Any?, property: KProperty<*>): String { | ||
markDependencyNotationsUsage() | ||
return name | ||
} | ||
|
||
inner class Module internal constructor( | ||
val name: String, | ||
val isBom: Boolean | ||
) { | ||
@PublishedApi | ||
internal fun markDependencyNotationsUsage() { | ||
if (isBom && usePlatformConstraints.not()) { | ||
if (haveDependencyNotationsBeenUsed && !isRunningTests) { | ||
error("You are trying to use a BoM ($name), but dependency notations relying on it have been declared before! Declare the BoM first to fix this issue.") | ||
} | ||
} | ||
if (isBom) usePlatformConstraints = true | ||
haveDependencyNotationsBeenUsed = true | ||
} | ||
} | ||
} |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
105 changes: 105 additions & 0 deletions
105
plugins/dependencies/src/main/kotlin/dependencies/Http4k.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import de.fayard.refreshVersions.core.internal.DependencyGroup | ||
|
||
|
||
object Http4k : DependencyGroup( | ||
group = "org.http4k", | ||
usePlatformConstraints = false, | ||
rawRule = """ | ||
org.http4k:http4k-* | ||
^^^^^^ | ||
""".trimIndent() | ||
) { | ||
val bom by module("http4k-bom", isBom = true) | ||
|
||
val aws by module("http4k-aws") | ||
val cloudnative by module("http4k-cloudnative") | ||
val contract by module("http4k-contract") | ||
val core by module("http4k-core") | ||
val graphql by module("http4k-graphql") | ||
val incubator by module("http4k-incubator") | ||
val jsonrpc by module("http4k-jsonrpc") | ||
val metricsMicrometer by module("http4k-metrics-micrometer") | ||
val multipart by module("http4k-multipart") | ||
val opentelemetry by module("http4k-opentelemetry") | ||
val realtimeCore by module("http4k-realtime-core") | ||
val resilience4j by module("http4k-resilience4j") | ||
val securityOauth by module("http4k-security-oauth") | ||
|
||
val client = Client | ||
|
||
object Client : DependencyGroup(group, usePlatformConstraints = true) { | ||
val apache by module("http4k-client-apache") | ||
val apacheAsync by module("http4k-client-apache-async") | ||
val apache4 by module("http4k-client-apache4") | ||
val apache4Async by module("http4k-client-apache4-async") | ||
val jetty by module("http4k-client-jetty") | ||
val okhttp by module("http4k-client-okhttp") | ||
val websocket by module("http4k-client-websocket") | ||
} | ||
|
||
val format = Format | ||
|
||
object Format : DependencyGroup(group, usePlatformConstraints = true) { | ||
val argo by module("http4k-format-argo") | ||
val core by module("http4k-format-core") | ||
val gson by module("http4k-format-gson") | ||
val jackson by module("http4k-format-jackson") | ||
val jacksonXml by module("http4k-format-jackson-xml") | ||
val jacksonYaml by module("http4k-format-jackson-yaml") | ||
val klaxon by module("http4k-format-klaxon") | ||
val kotlinxSerialization by module("http4k-format-kotlinx-serialization") | ||
val moshi by module("http4k-format-moshi") | ||
val xml by module("http4k-format-xml") | ||
} | ||
|
||
|
||
val server = Server | ||
|
||
object Server : DependencyGroup(group, usePlatformConstraints = true) { | ||
val apache by module("http4k-server-apache") | ||
val apache4 by module("http4k-server-apache4") | ||
val jetty by module("http4k-server-jetty") | ||
val ktorcio by module("http4k-server-ktorcio") | ||
val ktornetty by module("http4k-server-ktornetty") | ||
val netty by module("http4k-server-netty") | ||
val ratpack by module("http4k-server-ratpack") | ||
val undertow by module("http4k-server-undertow") | ||
} | ||
|
||
val serverless = Serverless | ||
|
||
object Serverless : DependencyGroup(group, usePlatformConstraints = true) { | ||
val alibaba by module("http4k-serverless-alibaba") | ||
val azure by module("http4k-serverless-azure") | ||
val gcf by module("http4k-serverless-gcf") | ||
val lambda by module("http4k-serverless-lambda") | ||
val lambdaRuntime by module("http4k-serverless-lambda-runtime") | ||
val openwhisk by module("http4k-serverless-openwhisk") | ||
val tencent by module("http4k-serverless-tencent") | ||
} | ||
|
||
val template = Template | ||
|
||
object Template : DependencyGroup(group, usePlatformConstraints = true) { | ||
val core by module("http4k-template-core") | ||
val dust by module("http4k-template-dust") | ||
val freemarker by module("http4k-template-freemarker") | ||
val handlebars by module("http4k-template-handlebars") | ||
val jade4j by module("http4k-template-jade4j") | ||
val pebble by module("http4k-template-pebble") | ||
val thymeleaf by module("http4k-template-thymeleaf") | ||
} | ||
|
||
val testing = Testing | ||
|
||
object Testing : DependencyGroup(group, usePlatformConstraints = true) { | ||
val approval by module("http4k-testing-approval") | ||
val chaos by module("http4k-testing-chaos") | ||
val hamkrest by module("http4k-testing-hamkrest") | ||
val kotest by module("http4k-testing-kotest") | ||
val servirtium by module("http4k-testing-servirtium") | ||
val strikt by module("http4k-testing-strikt") | ||
val webdriver by module("http4k-testing-webdriver") | ||
} | ||
} | ||
|
37 changes: 37 additions & 0 deletions
37
plugins/dependencies/src/main/kotlin/dependencies/Kodein.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
@file:Suppress("PackageDirectoryMismatch", "SpellCheckingInspection", "unused") | ||
|
||
import de.fayard.refreshVersions.core.internal.DependencyGroup | ||
import org.gradle.api.Incubating | ||
import org.gradle.kotlin.dsl.IsNotADependency | ||
|
||
/** | ||
* painless Kotlin dependency injection | ||
* | ||
* - [Official website here](https://kodein.org/di/) | ||
* - GitHub page: [Kodein-Framework/Kodein-DI](https://github.com/Kodein-Framework/Kodein-DI) | ||
* - [GitHub Releases here](https://github.com/Kodein-Framework/Kodein-DI/releases) | ||
*/ | ||
@Incubating | ||
object Kodein: IsNotADependency { | ||
|
||
val di = DI | ||
|
||
object DI : DependencyGroup( | ||
group = "org.kodein.di", | ||
usePlatformConstraints = false, | ||
rawRule = """ | ||
org.kodein.di:kodein-di(-*) | ||
^^^^^^^^^ | ||
""".trimIndent() | ||
) { | ||
val androidCore by module("kodein-di-framework-android-core") | ||
val androidSupport by module("kodein-di-framework-android-support") | ||
val androidx by module("kodein-di-framework-android-x") | ||
val configurableJS by module("kodein-di-conf-js") | ||
val configurableJvm by module("kodein-di-conf-jvm") | ||
val js by module("kodein-di-js") | ||
val jsr330 by module("kodein-di-jxinject-jvm") | ||
val ktor by module("kodein-di-framework-ktor-server-jvm") | ||
val tornadofx by module("kodein-di-framework-tornadofx-jvm") | ||
} | ||
} |
Oops, something went wrong.