diff --git a/CHANGELOG.md b/CHANGELOG.md
index e2df779..7bcd4d3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,10 +10,18 @@
Refactor development server implementation to use [jpenilla/run-task](https://github.com/jpenilla/run-task/) plugin and integrate run-paper for server execution,
improving maintainability and compatibility with various server versions.
- **Breaking change!**
- Rename `bukkit.meta { ... }` to `bukkit.plugin { ... }`.
- - Task `:parsePluginMetaFile` and `:mergePluginMeta` renamed to `:parsePluginYaml` and `:mergePluginYaml` respectively.
- - `bukkit.disableMetaGeneration()` replaced by `bukkit.plugin.disablePluginYamlGeneration()`
- - Package `.meta` renamed to `.plugin` to reflect this change
+ Use [jpenilla/resource-factory](https://github.com/jpenilla/resource-factory) to generate `plugin.yml`.
+ This change comes with some renames:
+ - Configuration block `bukkit.meta { ... }` -> `bukkit.plugin { ... }`
+ - Property `bukkit.plugin.url` -> `bukkit.plugin.website`
+ - Task `:parsePluginMetaFile` -> `:parsePluginYaml`
+ - Task `:mergePluginMeta` has been dropped. Use `:mainResourceFactory` instead
+ - Package `ru.endlesscode.bukkitgradle.meta` -> `ru.endlesscode.bukkitgradle.plugin`
+- Change API for disabling `plugin.yml` generation:
+ ```diff
+ -bukkit.disableMetaGeneration()
+ +bukkit.generatePluginYaml.set(false)
+ ```
- Set the default [JVM toolchain](https://docs.gradle.org/current/userguide/toolchains.html) version
instead of setting JVM target and source compatibility to 1.8.
By default, the minimal supported JVM version compatible with the specified `bukkit.server.version` is used.
diff --git a/README.md b/README.md
index 3bf736f..023cb33 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ Gradle utilities to simplify Bukkit/Spigot plugins writing and debugging.
- [Installation](#installation)
- - [First steps](#first-steps)
+ - [Quick Start](#quick-start)
- [Configuration](#configuration)
- [Repositories and Dependencies](#repositories-and-dependencies)
- [Running Dev server](#running-dev-server)
@@ -21,7 +21,6 @@ Gradle utilities to simplify Bukkit/Spigot plugins writing and debugging.
#### Features:
-- Automatically applies plugin: java
- Sets up compiler encoding to UTF-8
- Sets archivesBaseName to plugin name
- Supports APIs: Bukkit, CraftBukkit, Spigot, Paper
@@ -35,33 +34,22 @@ Gradle utilities to simplify Bukkit/Spigot plugins writing and debugging.
## Installation
-[BukkitGradle on plugins.gradle.org](https://plugins.gradle.org/plugin/ru.endlesscode.bukkitgradle)
-> **Note:** Gradle 8.0+ is required
+> [!NOTE]
+> BukkitGradle requires Gradle 8.0+ to run
-#### With new plugins mechanism
```kotlin
plugins {
id("ru.endlesscode.bukkitgradle") version "0.10.1"
}
```
-#### With buildscript and apply
-```groovy
-buildscript {
- repositories {
- mavenCentral()
- }
- dependencies {
- classpath("gradle.plugin.ru.endlesscode:bukkit-gradle:0.10.1")
- }
-}
+[BukkitGradle on plugins.gradle.org](https://plugins.gradle.org/plugin/ru.endlesscode.bukkitgradle)
-apply(plugin: "ru.endlesscode.bukkitgradle")
-```
+
-#### Snapshots
+Using snapshots
-If you want to use snapshots, you can add jitpack repository to `settings.gradle` and use version `develop-SNAPSHOT`:
+To use snapshots, add jitpack repository to the `settings.gradle.kts` and specify version `develop-SNAPSHOT`:
```kotlin
// settings.gradle
@@ -82,88 +70,86 @@ plugins {
}
```
-### First steps
-Simple `build.gradle` file that use BukkitGradle:
+
+
+### Quick Start
+
+Apply the plugin and configure project's `group`, `description` and `version`.
+These values will be used to generate the `plugin.yml` file:
+
```kotlin
plugins {
id("ru.endlesscode.bukkitgradle") version "0.10.1"
}
-
-// Project information
+
group = "com.example.myplugin"
-description = "My first Bukkit plugin with Gradle"
+description = "My first Bukkit plugin built by Gradle"
version = "0.1"
-// Let's add needed API to project
+bukkit {
+ apiVersion = "1.16.5"
+}
+
+// Add the necessary API to the project
dependencies {
compileOnly(bukkitApi())
- // see section 'Dependencies' for more info
+ // See the 'Dependencies' section for more info
}
```
-> **Note:** `compileOnly` - it's like `provided` scope in Maven.
-It means that this dependency will not be included to your final jar.
-It's enough!
-Will be hooked the latest version of Bukkit and automatically generated `plugin.yml` with next content:
+That's it!
+During the plugin compilation `plugin.yml` will be generated with the following content:
+
```yaml
+api-version: '1.16'
name: MyPlugin
-description: My first Bukkit plugin with Gradle
+version: '0.1'
main: com.example.myplugin.MyPlugin
-version: 0.1
-api-version: 1.16
+description: My first Bukkit plugin built by Gradle
```
-> **Note:** Main class built by following pattern: `.`
+
+> [!NOTE]
+> By default, main class is built by the following pattern: `.`
+
+Next, you might need to [configure](#configuration) `plugin.yml` content or [run dev server](#running-dev-server).
## Configuration
-You can configure attributes that will be placed to `plugin.yml`:
+
+The `plugin.yml` content can be configured using `bukkit.plugin { ... }` block.
+
```kotlin
-// Override default configurations
bukkit {
- // Version of API (if you will not set this property, will be used latest version at moment of BukkitGradle release)
+ // Version of API. By default, 1.16.5 is used
apiVersion = "1.15.2"
- // Attributes for plugin.yml
+ // Configure plugin.yml content
plugin {
- name.set("MyPlugin")
- description.set("My amazing plugin, that doing nothing")
- main.set("com.example.plugin.MyPlugin")
- version.set("1.0")
- url.set("http://www.example.com") // Attribute website
- authors.set(["OsipXD", "Contributors"])
+ name = "MyPlugin"
+ description = "My amazing plugin"
+ main = "com.example.plugin.MyPlugin"
+ version = "1.0"
+ authors = listOf("osipxd", "contributors")
+ depend = listOf("Vault", "Mimic")
}
}
```
-Will be generated `plugin.yml` file:
-```yaml
-name: MyPlugin
-description: My amazing plugin, that doing nothing
-main: com.example.plugin.MyPlugin
-version: 1.0
-api-version: 1.15
-website: http://www.example.com
-authors: [OsipXD, Contributors]
-```
-
-If you want to add unsupported by BukkitGradle attributes, like a `depend`, `commands` etc.
-Create `plugin.yml` file and put custom attributes there.
-
## Repositories and Dependencies
-BukkitGradle provides short extension-functions to add common repositories and dependencies.
-There are list of its.
-Usage example:
+BukkitGradle provides shortcuts to add common repositories and dependencies:
+
```kotlin
repositories {
- spigot() // Adds spigot repo
+ spigot()
}
dependencies {
- compileOnly(paperApi()) // Adds paper-api dependency
+ compileOnly(paperApi())
}
```
-#### Repositories:
+#### Repositories
+
Name | Url
----------------|-------------------------------------------------------------------
spigot | https://hub.spigotmc.org/nexus/content/repositories/snapshots/
@@ -176,7 +162,8 @@ dependencies {
aikar | https://repo.aikar.co/content/groups/aikar/
codemc | https://repo.codemc.org/repository/maven-public/
-#### Dependencies:
+#### Dependencies
+
Some dependencies also add a repository needed for them.
Name | Signature | Adds repository
@@ -188,7 +175,7 @@ Some dependencies also add a repository needed for them.
**Note:** `$apiVersion` - is `${version}-R0.1-SNAPSHOT` (where `$version` is `bukkit.version`)
-If you need more extension-functions, [create issue][issue].
+If you need more extension-functions, [file an issue][issue].
## Running Dev server
@@ -263,21 +250,29 @@ bukkit {
## Migration Guide
-### Upgrade from 0.8.x
+### Upgrade from 0.10.x
-1. Update gradle to 6.6 or newer:
- ```shell
- $ ./gradlew wrapper --gradle-version 6.7.1
- ```
-1. Use syntax `.set` in `bukkit.meta` instead of `=`:
+1. Update Gradle to 8.0 or newer (the latest version is recommended):
+```shell
+./gradlew wrapper --gradle-version 8.13
+```
+
+2. Replace deprecated and removed APIs:
```diff
bukkit {
- meta {
- - desctiption = "My plugin's description"
- + description.set("My plugin's description")
+ - meta {
+ + plugin {
+ name = "MyPlugin"
+ - url = "https://example.com/"
+ + website = "https://example.com/"
}
}
- ```
+ ```
+
+3. If you have `plugin.yml`, move it's content to `bukkit.plugin { ... }` block
+
+### Upgrade from 0.8.x
+
1. Use `bukkit.apiVersion` instead of `bukkit.version`:
```diff
bukkit {
@@ -285,7 +280,7 @@ bukkit {
+ apiVersion = "1.16.4"
}
```
-1. Use `build.server` block instead of `build.run`:
+2. Use `build.server` block instead of `build.run`:
```diff
bukkit {
- run {
@@ -294,7 +289,7 @@ bukkit {
}
}
```
-1. Update arguments assignment syntax:
+3. Update arguments assignment syntax:
```diff
bukkit {
server {
@@ -304,7 +299,7 @@ bukkit {
}
}
```
-1. Replace removed APIs:
+4. Replace removed APIs:
```diff
repositories {
- destroystokyo()
@@ -319,8 +314,8 @@ bukkit {
+ compileOnly(spigot())
}
```
-1. Remove `q` and `qq` functions calls in `meta { ... }`
-1. Check generated plugin.yml contents after build.
+5. Remove `q` and `qq` functions calls in `meta { ... }`
+6. Check generated plugin.yml contents after build.
If there are any problems, [create an issue][issue].
diff --git a/build.gradle.kts b/build.gradle.kts
index af984b1..c775ad3 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -29,7 +29,7 @@ repositories {
dependencies {
implementation("xyz.jpenilla.run-paper:xyz.jpenilla.run-paper.gradle.plugin:2.3.1")
- implementation("de.undercouch:gradle-download-task:5.6.0")
+ implementation("xyz.jpenilla.resource-factory:xyz.jpenilla.resource-factory.gradle.plugin:1.2.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.1")
implementation("com.charleskorn.kaml:kaml:0.74.0")
testImplementation("junit:junit:4.13.1")
diff --git a/src/main/kotlin/Bukkit.kt b/src/main/kotlin/Bukkit.kt
index 71ef34e..d93a4a7 100644
--- a/src/main/kotlin/Bukkit.kt
+++ b/src/main/kotlin/Bukkit.kt
@@ -1,16 +1,14 @@
package ru.endlesscode.bukkitgradle
import org.gradle.api.provider.Provider
-import ru.endlesscode.bukkitgradle.plugin.extension.PluginConfiguration
+import ru.endlesscode.bukkitgradle.plugin.plugin
import ru.endlesscode.bukkitgradle.server.extension.ServerConfiguration
+import xyz.jpenilla.resourcefactory.bukkit.BukkitPluginYaml
public interface Bukkit {
- /** Plugin plugin. */
- public val plugin: PluginConfiguration
-
@Deprecated("Use 'plugin' field instead", ReplaceWith("plugin"))
- public val meta: PluginConfiguration
+ public val meta: BukkitPluginYaml
get() = plugin
/** Dev server configuration. */
@@ -20,7 +18,10 @@ public interface Bukkit {
public val apiVersion: Provider
/** Plugin Meta generation enabled. */
- @Deprecated("Use 'plugin.generatePluginYaml' instead", ReplaceWith("plugin.generatePluginYaml"))
+ @Deprecated("Use 'generatePluginYaml' instead", ReplaceWith("generatePluginYaml"))
public val generateMeta: Provider
- get() = plugin.generatePluginYaml
+ get() = generatePluginYaml
+
+ /** Whether plugin.yml generation enabled or not. */
+ public val generatePluginYaml: Provider
}
diff --git a/src/main/kotlin/BukkitExtension.kt b/src/main/kotlin/BukkitExtension.kt
index fb33d3f..8cf2adc 100644
--- a/src/main/kotlin/BukkitExtension.kt
+++ b/src/main/kotlin/BukkitExtension.kt
@@ -7,16 +7,19 @@ import org.gradle.api.provider.Property
import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.property
import ru.endlesscode.bukkitgradle.extensions.finalizedOnRead
-import ru.endlesscode.bukkitgradle.plugin.extension.PluginConfigurationImpl
+import ru.endlesscode.bukkitgradle.plugin.plugin
import ru.endlesscode.bukkitgradle.server.ServerConstants
import ru.endlesscode.bukkitgradle.server.extension.ServerConfigurationImpl
+import xyz.jpenilla.resourcefactory.bukkit.BukkitPluginYaml
public open class BukkitExtension internal constructor(
- public final override val plugin: PluginConfigurationImpl,
public final override val server: ServerConfigurationImpl,
objects: ObjectFactory,
) : Bukkit {
+ override val generatePluginYaml: Property = objects.property()
+ .convention(true)
+
public final override val apiVersion: Property = objects.property()
.convention(ServerConstants.DEFAULT_VERSION)
.finalizedOnRead()
@@ -25,22 +28,22 @@ public open class BukkitExtension internal constructor(
body.execute(server)
}
- public fun plugin(body: Action) {
- body.execute(plugin)
- }
-
@Deprecated("Use 'plugin' instead", ReplaceWith("plugin(body)"))
- public fun meta(body: Action) {
- plugin(body)
+ public fun meta(body: Action) {
+ body.execute(plugin)
}
/** Disables plugin.yml generation. */
@Deprecated(
- "Use 'plugin.disablePluginYamlGeneration()' instead",
- ReplaceWith("plugin.disablePluginYamlGeneration()")
+ "Use 'generatePluginYaml.set(false)' instead",
+ ReplaceWith("generatePluginYaml.set(false)")
)
public fun disableMetaGeneration() {
- plugin.disablePluginYamlGeneration()
+ generatePluginYaml.set(false)
+ }
+
+ public companion object {
+ public const val NAME: String = "bukkit"
}
}
diff --git a/src/main/kotlin/BukkitGradlePlugin.kt b/src/main/kotlin/BukkitGradlePlugin.kt
index f4b771f..00edf50 100644
--- a/src/main/kotlin/BukkitGradlePlugin.kt
+++ b/src/main/kotlin/BukkitGradlePlugin.kt
@@ -2,14 +2,13 @@ package ru.endlesscode.bukkitgradle
import org.gradle.api.Plugin
import org.gradle.api.Project
-import org.gradle.api.plugins.JavaPluginExtension
+import org.gradle.api.plugins.JavaBasePlugin
+import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.kotlin.dsl.*
import ru.endlesscode.bukkitgradle.dependencies.Dependencies
-import ru.endlesscode.bukkitgradle.plugin.PluginConfigurationPlugin
-import ru.endlesscode.bukkitgradle.plugin.extension.PluginConfigurationImpl
-import ru.endlesscode.bukkitgradle.plugin.util.MinecraftVersion
-import ru.endlesscode.bukkitgradle.plugin.util.StringUtils
+import ru.endlesscode.bukkitgradle.extensions.java
+import ru.endlesscode.bukkitgradle.plugin.configurePluginYamlFeature
import ru.endlesscode.bukkitgradle.plugin.util.parsedApiVersion
import ru.endlesscode.bukkitgradle.plugin.util.resolveMinimalJavaVersion
import ru.endlesscode.bukkitgradle.server.DevServerPlugin
@@ -28,53 +27,34 @@ public class BukkitGradlePlugin : Plugin {
Dependencies.configureProject(project)
}
- /** Adds needed plugins. */
private fun Project.addPlugins() {
- val bukkit = extensions.create("bukkit", createPluginConfiguration(), ServerConfigurationImpl())
-
- with(plugins) {
- apply("java")
- apply()
- apply()
+ // Apply Java plugin, but only if another JVM-language plugin wasn't applied before
+ if (!plugins.hasPlugin(JavaBasePlugin::class)) {
+ plugins.apply(JavaPlugin::class)
}
- extensions.configure {
- toolchain {
- languageVersion.convention(bukkit.parsedApiVersion.map(::resolveMinimalJavaVersion))
- }
- }
- }
+ val bukkit = extensions.create(
+ BukkitExtension.NAME,
+ ServerConfigurationImpl(),
+ )
- private fun Project.createPluginConfiguration(): PluginConfigurationImpl {
- return PluginConfigurationImpl(objects).apply {
- name.convention(project.name)
- description.convention(provider { project.description })
- main.convention(name.map { "${project.group}.${StringUtils.toPascalCase(it)}" })
- version.convention(provider { project.version.toString() })
- apiVersion.convention(provider { bukkit.parsedApiVersion.get() }.map(::resolveDefaultApiVersion))
- url.convention(provider { providers.gradleProperty("url").orNull })
+ configurePluginYamlFeature(bukkit)
+ apply()
+
+ java.toolchain {
+ languageVersion.convention(bukkit.parsedApiVersion.map(::resolveMinimalJavaVersion))
}
}
- /** Sets encoding on compile to UTF-8. */
private fun Project.configureEncoding() {
tasks.withType().configureEach {
options.encoding = "UTF-8"
}
}
- /** Adds needed repositories. */
private fun Project.addRepositories() {
repositories {
mavenCentral()
}
}
-
- private fun resolveDefaultApiVersion(version: MinecraftVersion): String = when {
- // "API version" has been introduced in Spigot 1.13
- version < MinecraftVersion.V1_13_0 -> ""
- // From 1.20.5 and onward, a patch version is supported.
- version < MinecraftVersion.V1_20_5 -> version.withoutPatch().toString()
- else -> version.toString()
- }
}
diff --git a/src/main/kotlin/extensions/Accessors.kt b/src/main/kotlin/extensions/Accessors.kt
index e84c692..9bb9950 100644
--- a/src/main/kotlin/extensions/Accessors.kt
+++ b/src/main/kotlin/extensions/Accessors.kt
@@ -2,7 +2,16 @@ package ru.endlesscode.bukkitgradle.extensions
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginExtension
+import org.gradle.api.tasks.SourceSet
+import org.gradle.api.tasks.SourceSetContainer
import org.gradle.kotlin.dsl.the
+import xyz.jpenilla.resourcefactory.ResourceFactoryExtension
internal val Project.java: JavaPluginExtension
get() = the()
+
+internal val Project.sourceSets: SourceSetContainer
+ get() = the()
+
+internal val SourceSet.resourceFactory: ResourceFactoryExtension
+ get() = the()
diff --git a/src/main/kotlin/extensions/Provider.kt b/src/main/kotlin/extensions/Provider.kt
index 1ff73d5..5b6051b 100644
--- a/src/main/kotlin/extensions/Provider.kt
+++ b/src/main/kotlin/extensions/Provider.kt
@@ -1,11 +1,23 @@
package ru.endlesscode.bukkitgradle.extensions
-import org.gradle.api.Project
-import org.gradle.api.file.Directory
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
-import java.io.File
+import java.util.*
internal fun Property.finalizedOnRead(): Property = apply { finalizeValueOnRead() }
-internal fun Project.directoryProvider(file: () -> File?): Provider = layout.dir(provider(file))
+internal fun Property.finalizeAndGet(): T {
+ finalizeValue()
+ return get()
+}
+
+// See: https://github.com/gradle/gradle/issues/12388
+@Suppress("UnstableApiUsage")
+internal fun Provider.mapNotNull(transform: (T) -> R?): Provider {
+ return map { value: T ->
+ val transformedValue = transform(value)
+ Optional.ofNullable(transformedValue)
+ }
+ .filter(Optional::isPresent)
+ .map(Optional::get)
+}
diff --git a/src/main/kotlin/plugin/BukkitPluginYamlDefaults.kt b/src/main/kotlin/plugin/BukkitPluginYamlDefaults.kt
new file mode 100644
index 0000000..4b5a6f1
--- /dev/null
+++ b/src/main/kotlin/plugin/BukkitPluginYamlDefaults.kt
@@ -0,0 +1,79 @@
+@file:UseSerializers(PermissionDefaultSerializer::class)
+
+package ru.endlesscode.bukkitgradle.plugin
+
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.UseSerializers
+import kotlinx.serialization.descriptors.PrimitiveKind
+import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
+import kotlinx.serialization.descriptors.SerialDescriptor
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
+import xyz.jpenilla.resourcefactory.bukkit.BukkitPluginYaml
+import xyz.jpenilla.resourcefactory.bukkit.Permission.Default as PermissionDefault
+
+/**
+ * Should be synced with [BukkitPluginYaml.Serializable].
+ * We can't use the existing class as we want all fields to be nullable.
+ */
+@Serializable
+internal data class BukkitPluginYamlDefaults(
+ val apiVersion: String? = null,
+ val name: String? = null,
+ val version: String? = null,
+ val main: String? = null,
+ val description: String? = null,
+ val load: BukkitPluginYaml.PluginLoadOrder? = null,
+ val author: String? = null,
+ val authors: List? = null,
+ val website: String? = null,
+ val depend: List? = null,
+ val softdepend: List? = null,
+ val loadbefore: List? = null,
+ val prefix: String? = null,
+ val defaultPermission: PermissionDefault? = null,
+ val provides: List? = null,
+ val libraries: List? = null,
+ val commands: Map = emptyMap(),
+ val permissions: Map = emptyMap(),
+ val foliaSupported: Boolean? = null,
+ val paperPluginLoader: String? = null,
+ val paperSkipLibraries: Boolean? = null,
+) {
+
+ @Serializable
+ internal data class Command(
+ val description: String? = null,
+ val aliases: List? = null,
+ val permission: String? = null,
+ val permissionMessage: String? = null,
+ val usage: String? = null,
+ )
+
+ @Serializable
+ internal data class Permission(
+ val description: String? = null,
+ val default: PermissionDefault? = null,
+ val children: Map? = null,
+ )
+}
+
+internal object PermissionDefaultSerializer : KSerializer {
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(
+ "xyz.jpenilla.resourcefactory.bukkit.Permission.Default",
+ PrimitiveKind.STRING,
+ )
+
+ override fun deserialize(decoder: Decoder): PermissionDefault {
+ val string = decoder.decodeString()
+ return requireNotNull(PermissionDefault.values().find { it.serialized.equals(string, ignoreCase = true) }) {
+ val knownValues = PermissionDefault.values().joinToString { it.serialized }
+ "Unknown permission default '$string'. Allowed: $knownValues"
+ }
+ }
+
+ override fun serialize(encoder: Encoder, value: PermissionDefault) {
+ encoder.encodeString(value.serialized)
+ }
+}
diff --git a/src/main/kotlin/plugin/PluginConfigurationPlugin.kt b/src/main/kotlin/plugin/PluginConfigurationPlugin.kt
deleted file mode 100644
index 2f0893d..0000000
--- a/src/main/kotlin/plugin/PluginConfigurationPlugin.kt
+++ /dev/null
@@ -1,69 +0,0 @@
-package ru.endlesscode.bukkitgradle.plugin
-
-import com.charleskorn.kaml.SequenceStyle
-import com.charleskorn.kaml.Yaml
-import com.charleskorn.kaml.YamlConfiguration
-import org.gradle.api.Plugin
-import org.gradle.api.Project
-import org.gradle.api.file.CopySpec
-import org.gradle.api.file.DuplicatesStrategy
-import org.gradle.kotlin.dsl.get
-import org.gradle.kotlin.dsl.named
-import org.gradle.kotlin.dsl.register
-import ru.endlesscode.bukkitgradle.bukkit
-import ru.endlesscode.bukkitgradle.extensions.java
-import ru.endlesscode.bukkitgradle.plugin.extension.PluginConfigurationImpl
-import ru.endlesscode.bukkitgradle.plugin.task.MergePluginYaml
-import ru.endlesscode.bukkitgradle.plugin.task.ParsePluginYaml
-import java.io.File
-
-public class PluginConfigurationPlugin : Plugin {
-
- override fun apply(project: Project) {
- val yaml = Yaml(
- configuration = YamlConfiguration(
- encodeDefaults = false,
- sequenceStyle = SequenceStyle.Flow
- )
- )
-
- val parsePluginYaml = project.tasks.register("parsePluginYaml") {
- val bukkit = project.bukkit
-
- this.yaml = yaml
- this.plugin = bukkit.plugin as PluginConfigurationImpl
- this.pluginYamlFile.set(project.findPluginYaml())
-
- val predicate = bukkit.plugin.generatePluginYaml
- onlyIf { predicate.get() }
- }
-
- val mergePluginYaml = project.tasks.register("mergePluginYaml") {
- val bukkit = project.bukkit
-
- this.yaml = yaml
- this.plugin = bukkit.plugin
- pluginYaml.set(parsePluginYaml.map { it.pluginYaml.get() })
-
- val predicate = bukkit.plugin.generatePluginYaml
- onlyIf { predicate.get() }
- }
-
- project.tasks.named("processResources") {
- from(mergePluginYaml)
- duplicatesStrategy = DuplicatesStrategy.INCLUDE
- }
- }
-
- /** Finds and returns project's plugin.yaml if it exists. */
- private fun Project.findPluginYaml(): File? {
- val mainSourceSet = java.sourceSets["main"]
- val resourceDir = mainSourceSet.resources.srcDirs.first()
-
- return File(resourceDir, FILE_NAME).takeIf { it.isFile }
- }
-
- internal companion object {
- const val FILE_NAME: String = "plugin.yml"
- }
-}
diff --git a/src/main/kotlin/plugin/PluginYaml.kt b/src/main/kotlin/plugin/PluginYaml.kt
deleted file mode 100644
index 78a0666..0000000
--- a/src/main/kotlin/plugin/PluginYaml.kt
+++ /dev/null
@@ -1,111 +0,0 @@
-package ru.endlesscode.bukkitgradle.plugin
-
-import kotlinx.serialization.SerialName
-import kotlinx.serialization.Serializable
-
-@Serializable
-internal data class PluginYaml(
-
- /** The class of the plugin that extends JavaPlugin. */
- val main: String? = null,
-
- /** Name of the plugin. */
- val name: String? = null,
-
- /** A human friendly description of the functionality the plugin provides. */
- val description: String? = null,
-
- /** The name to use when logging to console instead of the plugin's name. */
- val prefix: String? = null,
-
- /** The version of the plugin. */
- val version: String? = null,
-
- /** The version of the API that plugin use. */
- @SerialName("api-version")
- val apiVersion: String? = null,
-
- /** Explicitly state when a plugin should be loaded. */
- val load: String? = null,
-
- /** Uniquely identifies who developed this plugin. */
- val author: String? = null,
-
- /**
- * Allows listing multiple authors if it is a collaborative project.
- * @see author
- */
- val authors: List? = null,
-
- /** The contributors to the plugin that aren't the managing author(s). */
- val contributors: List? = null,
-
- /** The plugin's or author's website. */
- val website: String? = null,
-
- /** A list of plugins that your plugin requires to load. */
- val depend: List? = null,
-
- /** A list of plugins that are required for your plugin to have full functionality. */
- val softdepend: List? = null,
-
- /** A list of plugins that should be loaded after your plugin. */
- val loadbefore: List? = null,
-
- /**
- * This can be used to tell the server that this plugin will provide the functionality
- * of some library or other plugin (like an alias system).
- * Plugins that (soft)depend on the other plugin will treat your plugin
- * as if the other plugin exists when resolving dependencies or using `PluginManager#getPlugin(String)`.
- */
- val provides: List? = null,
-
- /** A list of libraries your plugin needs which can be loaded from Maven Central. */
- val libraries: List? = null,
-
- /** The name of a command the plugin wishes to register, as well as an optional list of command attributes. */
- val commands: Map? = null,
-
- /** Permission that the plugin wishes to register. */
- val permissions: Map? = null,
-
- /** The default value that permissions that don't have a `default` specified will have. */
- @SerialName("default-permission")
- val defaultPermission: String? = null,
-) : java.io.Serializable
-
-@Serializable
-internal data class PluginCommand(
-
- /** A short description of what the command does. */
- val description: String? = null,
-
- /** Alternate command names a user may use instead. */
- val aliases: List? = null,
-
- /** The most basic permission node required to use the command. */
- val permission: String? = null,
-
- /**
- * A no-permission message which is displayed to a user if they do not have the required permission
- * to use this command.
- */
- @SerialName("permission-message")
- val permissionMessage: String? = null,
-
- /** A short description of how to use this command. */
- val usage: String? = null
-) : java.io.Serializable
-
-@Serializable
-internal data class PluginPermission(
-
- /** A short description of what this permission allows. */
- val description: String? = null,
-
- /** The default value of the permission. */
- val default: String? = null,
-
- /** Children for the permission. */
- val children: Map? = null
-) : java.io.Serializable
diff --git a/src/main/kotlin/plugin/PluginYamlFeature.kt b/src/main/kotlin/plugin/PluginYamlFeature.kt
new file mode 100644
index 0000000..6a2dc56
--- /dev/null
+++ b/src/main/kotlin/plugin/PluginYamlFeature.kt
@@ -0,0 +1,112 @@
+package ru.endlesscode.bukkitgradle.plugin
+
+import org.gradle.api.Project
+import org.gradle.api.file.RegularFile
+import org.gradle.api.plugins.ExtensionAware
+import org.gradle.api.provider.Provider
+import org.gradle.api.tasks.SourceSet
+import org.gradle.kotlin.dsl.*
+import ru.endlesscode.bukkitgradle.Bukkit
+import ru.endlesscode.bukkitgradle.BukkitExtension
+import ru.endlesscode.bukkitgradle.extensions.finalizeAndGet
+import ru.endlesscode.bukkitgradle.extensions.mapNotNull
+import ru.endlesscode.bukkitgradle.extensions.resourceFactory
+import ru.endlesscode.bukkitgradle.extensions.sourceSets
+import ru.endlesscode.bukkitgradle.plugin.task.ParsePluginYaml
+import ru.endlesscode.bukkitgradle.plugin.util.MinecraftVersion
+import ru.endlesscode.bukkitgradle.plugin.util.StringUtils
+import ru.endlesscode.bukkitgradle.plugin.util.parsedApiVersion
+import xyz.jpenilla.resourcefactory.ExecuteResourceFactories
+import xyz.jpenilla.resourcefactory.ResourceFactoryPlugin
+import xyz.jpenilla.resourcefactory.bukkit.BukkitPluginYaml
+import xyz.jpenilla.resourcefactory.bukkit.bukkitPluginYaml
+
+private const val PLUGIN_EXTENSION_NAME: String = "plugin"
+private const val SOURCE_SET_NAME: String = "main" // Make it configurable, maybe?
+internal const val PLUGIN_YML: String = "plugin.yml"
+
+internal fun Project.configurePluginYamlFeature(bukkit: BukkitExtension) {
+ project.apply()
+
+ val bukkitPluginYaml = bukkitPluginYaml {
+ setConventionsFromProjectMeta(project, bukkit)
+ }
+ (bukkit as ExtensionAware).extensions.add(PLUGIN_EXTENSION_NAME, bukkitPluginYaml)
+
+ val mainSourceSet = sourceSets.named(SOURCE_SET_NAME) {
+ resourceFactory.factory(bukkitPluginYaml.resourceFactory())
+ }
+
+ val parsePluginYamlProvider = tasks.register("parsePluginYaml") {
+ pluginYaml.set(bukkitPluginYaml)
+ pluginYamlFile.set(findPluginYaml(mainSourceSet))
+
+ onlyIf { bukkit.generatePluginYaml.finalizeAndGet() }
+ }
+
+ tasks.named("${SOURCE_SET_NAME}ResourceFactory") {
+ val generatePluginYaml = bukkit.generatePluginYaml.finalizeAndGet()
+ onlyIf("Flag generatePluginYaml is enabled") { generatePluginYaml }
+ if (!generatePluginYaml) return@named
+
+ val parsePluginYaml = parsePluginYamlProvider.get()
+
+ // Switch to in-place generation mode if the plugin.yml exists
+ if (parsePluginYaml.pluginYamlFile.isPresent) {
+ dependsOn(parsePluginYaml)
+
+ val pluginYamlFile = parsePluginYaml.pluginYamlFile.get().asFile
+ outputDir.set(pluginYamlFile.parentFile)
+ // Deduplicate resource dirs after changing outputDir
+ mainSourceSet.configure {
+ resources.setSrcDirs(resources.srcDirs.distinct())
+ }
+ }
+ }
+}
+
+private fun Project.findPluginYaml(sourceSetProvider: Provider): Provider {
+ val fileProvider = sourceSetProvider.mapNotNull { sourceSet ->
+ sourceSet.resources.sourceDirectories
+ .map { it.resolve(PLUGIN_YML) }
+ .find { it.isFile }
+ }
+
+ return layout.file(fileProvider)
+}
+
+/**
+ * We use custom implementation of `setConventionsFromProjectMeta` that uses providers to defer project fields reading.
+ */
+private fun BukkitPluginYaml.setConventionsFromProjectMeta(project: Project, bukkit: BukkitExtension) {
+ name.convention(project.name) // Project name is immutable, no need to wrap it with provider
+ description.convention(project.provider { project.description })
+ version.convention(project.provider { project.version.toString() })
+ apiVersion.convention(bukkit.parsedApiVersion.map(::resolveDefaultApiVersion))
+
+ // Kept for backward compatibility
+ // TODO: This is a bit unobvious behavior, so probably we should remove defaults for these properties
+ main.convention(name.mapNotNull {
+ if (project.group.toString().isEmpty()) return@mapNotNull null
+ "${project.group}.${StringUtils.toPascalCase(it)}" }
+ )
+ website.convention(
+ project.providers.gradleProperty("url")
+ .orElse(project.providers.gradleProperty("website"))
+ )
+}
+
+private fun resolveDefaultApiVersion(version: MinecraftVersion): String = when {
+ // "API version" has been introduced in Spigot 1.13
+ version < MinecraftVersion.V1_13_0 -> ""
+ // From 1.20.5 and onward, a patch version is supported.
+ version < MinecraftVersion.V1_20_5 -> version.withoutPatch().toString()
+ else -> version.toString()
+}
+
+public val Bukkit.plugin: BukkitPluginYaml
+ get() = (this as ExtensionAware).the()
+
+public fun Bukkit.plugin(configure: BukkitPluginYaml.() -> Unit) {
+ (this as ExtensionAware).configure(configure)
+}
diff --git a/src/main/kotlin/plugin/extension/PluginConfiguration.kt b/src/main/kotlin/plugin/extension/PluginConfiguration.kt
deleted file mode 100644
index 9a796ff..0000000
--- a/src/main/kotlin/plugin/extension/PluginConfiguration.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-package ru.endlesscode.bukkitgradle.plugin.extension
-
-import org.gradle.api.provider.Provider
-import org.gradle.api.tasks.Input
-import org.gradle.api.tasks.Internal
-import org.gradle.api.tasks.Optional
-
-public interface PluginConfiguration {
-
- @get:Internal
- public val generatePluginYaml: Provider
-
- @get:Input
- public val name: Provider
-
- @get:Optional
- @get:Input
- public val description: Provider
-
- @get:Input
- public val main: Provider
-
- @get:Input
- public val version: Provider
-
- @get:Optional
- @get:Input
- public val apiVersion: Provider
-
- @get:Optional
- @get:Input
- public val url: Provider
-
- @get:Optional
- @get:Input
- public val authors: Provider>
-}
diff --git a/src/main/kotlin/plugin/extension/PluginConfigurationImpl.kt b/src/main/kotlin/plugin/extension/PluginConfigurationImpl.kt
deleted file mode 100644
index 3b400d6..0000000
--- a/src/main/kotlin/plugin/extension/PluginConfigurationImpl.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package ru.endlesscode.bukkitgradle.plugin.extension
-
-import org.gradle.api.model.ObjectFactory
-import org.gradle.api.provider.ListProperty
-import org.gradle.api.provider.Property
-import org.gradle.kotlin.dsl.listProperty
-import org.gradle.kotlin.dsl.property
-import ru.endlesscode.bukkitgradle.extensions.finalizedOnRead
-
-public class PluginConfigurationImpl(objects: ObjectFactory) : PluginConfiguration {
-
- private val _generatePluginYaml: Property = objects.property()
- .convention(true)
- .finalizedOnRead()
- override val generatePluginYaml: Property = _generatePluginYaml
-
- override val name: Property = objects.property()
- override val description: Property = objects.property()
- override val main: Property = objects.property()
- override val version: Property = objects.property()
- override val apiVersion: Property = objects.property()
- override val url: Property = objects.property()
- override val authors: ListProperty = objects.listProperty()
-
- /** Disables plugin.yaml parsing and generation. */
- public fun disablePluginYamlGeneration() {
- _generatePluginYaml.set(false)
- }
-}
diff --git a/src/main/kotlin/plugin/task/MergePluginYaml.kt b/src/main/kotlin/plugin/task/MergePluginYaml.kt
deleted file mode 100644
index 9a4434f..0000000
--- a/src/main/kotlin/plugin/task/MergePluginYaml.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-package ru.endlesscode.bukkitgradle.plugin.task
-
-import com.charleskorn.kaml.Yaml
-import kotlinx.serialization.encodeToString
-import org.gradle.api.DefaultTask
-import org.gradle.api.file.ProjectLayout
-import org.gradle.api.file.RegularFileProperty
-import org.gradle.api.provider.Property
-import org.gradle.api.provider.ProviderFactory
-import org.gradle.api.tasks.*
-import ru.endlesscode.bukkitgradle.TASKS_GROUP_BUKKIT
-import ru.endlesscode.bukkitgradle.plugin.PluginConfigurationPlugin
-import ru.endlesscode.bukkitgradle.plugin.PluginYaml
-import ru.endlesscode.bukkitgradle.plugin.extension.PluginConfiguration
-import java.io.File
-import javax.inject.Inject
-
-/**
- * Task that generates plugin.yml for bukkit plugin.
- *
- * @see ru.endlesscode.bukkitgradle.plugin.PluginConfigurationPlugin
- */
-public abstract class MergePluginYaml @Inject internal constructor(
- projectLayout: ProjectLayout,
- providers: ProviderFactory
-): DefaultTask() {
-
- @get:Internal
- internal lateinit var yaml: Yaml
-
- @get:Nested
- internal lateinit var plugin: PluginConfiguration
-
- @get:Input
- internal abstract val pluginYaml: Property
-
- @get:OutputFile
- public abstract val target: RegularFileProperty
-
- init {
- group = TASKS_GROUP_BUKKIT
- description = "Generate plugin.yml file"
-
- val defaultTargetProvider = providers.provider { File(temporaryDir, PluginConfigurationPlugin.FILE_NAME) }
- target.convention(projectLayout.file(defaultTargetProvider))
- }
-
- /** Writes plugin to a target file */
- @TaskAction
- public fun mergePluginYaml() {
- val merged = pluginYaml.get().copy(
- main = plugin.main.get(),
- name = plugin.name.get(),
- description = plugin.description.orNull,
- version = plugin.version.get(),
- apiVersion = plugin.apiVersion.orNull?.takeIf { it.isNotEmpty() },
- website = plugin.url.orNull,
- authors = plugin.authors.get().takeIf { it.isNotEmpty() }
- )
-
- target.get()
- .asFile
- .writeText(yaml.encodeToString(merged))
- }
-}
diff --git a/src/main/kotlin/plugin/task/ParsePluginYaml.kt b/src/main/kotlin/plugin/task/ParsePluginYaml.kt
index 81f761b..a61aaa9 100644
--- a/src/main/kotlin/plugin/task/ParsePluginYaml.kt
+++ b/src/main/kotlin/plugin/task/ParsePluginYaml.kt
@@ -1,69 +1,102 @@
package ru.endlesscode.bukkitgradle.plugin.task
-import com.charleskorn.kaml.EmptyYamlDocumentException
-import com.charleskorn.kaml.Yaml
-import com.charleskorn.kaml.decodeFromStream
+import com.charleskorn.kaml.*
import org.gradle.api.DefaultTask
+import org.gradle.api.GradleException
import org.gradle.api.file.RegularFileProperty
-import org.gradle.api.provider.Provider
-import org.gradle.api.provider.ProviderFactory
-import org.gradle.api.tasks.InputFile
-import org.gradle.api.tasks.Internal
-import org.gradle.api.tasks.Optional
-import org.gradle.api.tasks.TaskAction
+import org.gradle.api.provider.Property
+import org.gradle.api.tasks.*
import ru.endlesscode.bukkitgradle.TASKS_GROUP_BUKKIT
-import ru.endlesscode.bukkitgradle.plugin.PluginYaml
-import ru.endlesscode.bukkitgradle.plugin.extension.PluginConfigurationImpl
-import javax.inject.Inject
+import ru.endlesscode.bukkitgradle.plugin.BukkitPluginYamlDefaults
+import xyz.jpenilla.resourcefactory.bukkit.BukkitPluginYaml
+import xyz.jpenilla.resourcefactory.bukkit.Permission
-internal abstract class ParsePluginYaml @Inject constructor(
- providers: ProviderFactory
-) : DefaultTask() {
+internal abstract class ParsePluginYaml : DefaultTask() {
- @get:Internal
- lateinit var yaml: Yaml
+ private val yaml by lazy {
+ Yaml(
+ configuration = YamlConfiguration(
+ strictMode = false,
+ decodeEnumCaseInsensitive = true,
+ yamlNamingStrategy = YamlNamingStrategy.KebabCase,
+ )
+ )
+ }
@get:Internal
- lateinit var plugin: PluginConfigurationImpl
+ abstract val pluginYaml: Property
- @get:Optional
+ @get:SkipWhenEmpty
@get:InputFile
+ @get:PathSensitive(PathSensitivity.NONE)
abstract val pluginYamlFile: RegularFileProperty
- private var _pluginYaml: PluginYaml? = null
-
- @get:Internal
- val pluginYaml: Provider = providers.provider { checkNotNull(_pluginYaml) }
-
init {
group = TASKS_GROUP_BUKKIT
- description = "Parse plugin.yml file if it exists"
+ description = "Parse plugin.yml file if it exists and add its content as defaults to generation"
}
@TaskAction
- fun parse() {
- _pluginYaml = readFromFile()
+ fun parseAndSetDefaults() {
+ val defaults = readFromFile()
+ if (defaults != null) pluginYaml.get().applyConventions(defaults)
}
- /** Reads plugin.yaml from [pluginYamlFile] and adds conventions for specified fields. */
- private fun readFromFile(): PluginYaml {
- if (!pluginYamlFile.isPresent) return PluginYaml()
-
- val file = pluginYamlFile.get().asFile
- val pluginYaml = try {
- file.inputStream().use { yaml.decodeFromStream(it) }
+ private fun readFromFile(): BukkitPluginYamlDefaults? {
+ return try {
+ pluginYamlFile.get().asFile
+ .inputStream()
+ .use { yaml.decodeFromStream(it) }
} catch (cause: EmptyYamlDocumentException) {
- return PluginYaml()
+ logger.debug("plugin.yml is empty – skipping defaults setting", cause)
+ null
+ } catch (cause: Exception) {
+ throw GradleException("Failed to parse plugin.yml: ${cause.message}.\n" +
+ "Ensure the file is valid YAML that matches plugin.yml schema.", cause)
}
+ }
+}
- return pluginYaml.apply {
- main?.let(plugin.main::convention)
- name?.let(plugin.name::convention)
- description?.let(plugin.description::convention)
- version?.let(plugin.version::convention)
- apiVersion?.let(plugin.apiVersion::convention)
- website?.let(plugin.url::convention)
- authors?.let(plugin.authors::convention)
- }
+private fun BukkitPluginYaml.applyConventions(defaults: BukkitPluginYamlDefaults) {
+ defaults.main?.let(main::convention)
+ defaults.name?.let(name::convention)
+ defaults.description?.let(description::convention)
+ defaults.prefix?.let(prefix::convention)
+ defaults.version?.let(version::convention)
+ defaults.apiVersion?.let(apiVersion::convention)
+ defaults.load?.let(load::convention)
+ defaults.author?.let(author::convention)
+ defaults.authors?.let(authors::convention)
+ defaults.website?.let(website::convention)
+ defaults.depend?.let(depend::convention)
+ defaults.softdepend?.let(softDepend::convention)
+ defaults.loadbefore?.let(loadBefore::convention)
+ defaults.provides?.let(provides::convention)
+ defaults.libraries?.let(libraries::convention)
+ defaults.defaultPermission?.let(defaultPermission::convention)
+ defaults.foliaSupported?.let(foliaSupported::convention)
+ defaults.paperPluginLoader?.let(paperPluginLoader::convention)
+ defaults.paperSkipLibraries?.let(paperSkipLibraries::convention)
+
+ for ((name, command) in defaults.commands) {
+ commands.maybeCreate(name).applyConventions(command)
+ }
+
+ for ((name, permission) in defaults.permissions) {
+ permissions.maybeCreate(name).applyConventions(permission)
}
}
+
+private fun BukkitPluginYaml.Command.applyConventions(defaults: BukkitPluginYamlDefaults.Command) {
+ defaults.description?.let(description::convention)
+ defaults.aliases?.let(aliases::convention)
+ defaults.permission?.let(permission::convention)
+ defaults.permissionMessage?.let(permissionMessage::convention)
+ defaults.usage?.let(usage::convention)
+}
+
+private fun Permission.applyConventions(defaults: BukkitPluginYamlDefaults.Permission) {
+ defaults.description?.let(description::convention)
+ defaults.default?.let(default::convention)
+ defaults.children?.let(children::convention)
+}
diff --git a/src/main/kotlin/server/DevServerPlugin.kt b/src/main/kotlin/server/DevServerPlugin.kt
index 5968d15..04d9187 100644
--- a/src/main/kotlin/server/DevServerPlugin.kt
+++ b/src/main/kotlin/server/DevServerPlugin.kt
@@ -3,7 +3,6 @@ package ru.endlesscode.bukkitgradle.server
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.file.Directory
-import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskContainer
import org.gradle.api.tasks.TaskProvider
@@ -11,6 +10,7 @@ import org.gradle.jvm.toolchain.JavaToolchainService
import org.gradle.kotlin.dsl.*
import ru.endlesscode.bukkitgradle.Bukkit
import ru.endlesscode.bukkitgradle.bukkit
+import ru.endlesscode.bukkitgradle.extensions.java
import ru.endlesscode.bukkitgradle.plugin.util.resolveMinimalJavaVersion
import ru.endlesscode.bukkitgradle.server.extension.ServerConfiguration
import ru.endlesscode.bukkitgradle.server.task.CreateIdeaGradleRunConfiguration
@@ -54,7 +54,7 @@ public class DevServerPlugin : Plugin {
}
// RunPaperPlugin uses afterEvaluate under the hood, so we have to use afterEvaluate
- // to set our conventions after theirs
+ // to set our conventions after their ones
project.afterEvaluate { configureDefaultJvmForServer() }
val prepareServer = registerPrepareServerTask(runServer)
@@ -65,7 +65,7 @@ public class DevServerPlugin : Plugin {
private fun Project.configureDefaultJvmForServer() {
val toolchains = project.extensions.findByType() ?: return
- val spec = the().toolchain
+ val spec = java.toolchain
tasks.withType().configureEach {
javaLauncher.convention(
diff --git a/src/test/groovy/ru/endlesscode/bukkitgradle/BukkitGradlePluginSpec.groovy b/src/test/groovy/ru/endlesscode/bukkitgradle/BukkitGradlePluginSpec.groovy
index 96a4336..7d46aa3 100644
--- a/src/test/groovy/ru/endlesscode/bukkitgradle/BukkitGradlePluginSpec.groovy
+++ b/src/test/groovy/ru/endlesscode/bukkitgradle/BukkitGradlePluginSpec.groovy
@@ -7,11 +7,6 @@ class BukkitGradlePluginSpec extends PluginSpecification {
project.apply(plugin: BukkitGradlePlugin)
}
- def "when initialized - should add required plugins"() {
- expect: "java plugin added"
- project.pluginManager.hasPlugin("java")
- }
-
def "when initialized - should set default JVM toolchain"(String apiVersion, int jvmVersion) {
when: "apiVersion is set"
project.bukkit.apiVersion = apiVersion
diff --git a/src/test/groovy/ru/endlesscode/bukkitgradle/PluginSpecification.groovy b/src/test/groovy/ru/endlesscode/bukkitgradle/PluginSpecification.groovy
index 17a5a15..963e36e 100644
--- a/src/test/groovy/ru/endlesscode/bukkitgradle/PluginSpecification.groovy
+++ b/src/test/groovy/ru/endlesscode/bukkitgradle/PluginSpecification.groovy
@@ -82,6 +82,6 @@ class PluginSpecification extends Specification {
}
protected TaskOutcome taskOutcome(String task) {
- return result.task(task).outcome
+ return result.task(task)?.outcome
}
}
diff --git a/src/test/groovy/ru/endlesscode/bukkitgradle/plugin/task/GeneratePluginYamlSpec.groovy b/src/test/groovy/ru/endlesscode/bukkitgradle/plugin/task/GeneratePluginYamlSpec.groovy
new file mode 100644
index 0000000..1975050
--- /dev/null
+++ b/src/test/groovy/ru/endlesscode/bukkitgradle/plugin/task/GeneratePluginYamlSpec.groovy
@@ -0,0 +1,415 @@
+package ru.endlesscode.bukkitgradle.plugin.task
+
+
+import org.gradle.testkit.runner.TaskOutcome
+import ru.endlesscode.bukkitgradle.PluginSpecification
+import ru.endlesscode.bukkitgradle.plugin.PluginYamlFeatureKt
+import ru.endlesscode.bukkitgradle.util.CharsetUtils
+
+class GeneratePluginYamlSpec extends PluginSpecification {
+
+ private final static RESOURCE_FACTORY = ':mainResourceFactory'
+ private final static PARSE_PLUGIN_YAML = ':parsePluginYaml'
+
+ private File pluginYamlFile
+
+ def setup() {
+ pluginYamlFile = file("src/main/resources/$PluginYamlFeatureKt.PLUGIN_YML")
+
+ buildFile << """
+ bukkit.apiVersion = "1.16.2"
+ """.stripIndent()
+ }
+
+ def 'when run processResources - should also run resource factory'() {
+ when:
+ run(':processResources')
+
+ then:
+ taskOutcome(RESOURCE_FACTORY) == TaskOutcome.SUCCESS
+
+ and:
+ taskOutcome(PARSE_PLUGIN_YAML) == TaskOutcome.SUCCESS
+ }
+
+ def 'when run processResources - and plugin.yml generation disabled - should not run resource factory'() {
+ given:
+ buildFile << "bukkit.generatePluginYaml = false"
+
+ when:
+ run(':processResources')
+
+ then:
+ taskOutcome(RESOURCE_FACTORY) == TaskOutcome.SKIPPED
+
+ and:
+ taskOutcome(PARSE_PLUGIN_YAML) == null
+ }
+
+ def 'when run processResources - and plugin.yml doesnt exist - should skip parsing'() {
+ given:
+ pluginYamlFile.delete()
+
+ when:
+ run(':processResources')
+
+ then:
+ taskOutcome(RESOURCE_FACTORY) == TaskOutcome.SUCCESS
+
+ and:
+ taskOutcome(PARSE_PLUGIN_YAML) == null
+ }
+
+ def 'when run parsing - and plugin.yml doesnt exist - should show NO_SOURCE'() {
+ given:
+ pluginYamlFile.delete()
+
+ when:
+ run(PARSE_PLUGIN_YAML)
+
+ then:
+ taskOutcome(PARSE_PLUGIN_YAML) == TaskOutcome.NO_SOURCE
+ }
+
+ def 'when generate plugin.yml - should generate default plugin.yml successfully'() {
+ when:
+ run(RESOURCE_FACTORY)
+
+ then: "plugin file content corresponds to default config"
+ pluginYamlFile.text == """\
+ api-version: '1.16'
+ name: test-plugin
+ version: '1.0'
+ main: com.example.testplugin.TestPlugin
+ """.stripIndent()
+ }
+
+ def 'when generate plugin.yml - should set api-version'(String apiVersion, String expectedResult) {
+ when: "api version is $apiVersion"
+ buildFile << """
+ bukkit.apiVersion = "$apiVersion"
+ """.stripIndent()
+
+ and:
+ run(RESOURCE_FACTORY)
+
+ then: "plugin file content corresponds to default config"
+ pluginYamlFile.text == """\
+ api-version: $expectedResult
+ name: test-plugin
+ version: '1.0'
+ main: com.example.testplugin.TestPlugin
+ """.stripIndent()
+
+ where:
+ apiVersion | expectedResult
+ "1.16.5" | "'1.16'"
+ "1.20.4" | "'1.20'"
+ "1.20.5" | "1.20.5"
+ "1.21.1" | "1.21.1"
+ }
+
+ def 'when generate plugin.yml - and generate it again - should skip second task run'() {
+ when:
+ run(RESOURCE_FACTORY)
+ def firstRunOutcome = taskOutcome(RESOURCE_FACTORY)
+
+ and: "run generation again"
+ run(RESOURCE_FACTORY)
+ def secondRunOutcome = taskOutcome(RESOURCE_FACTORY)
+
+ then:
+ firstRunOutcome == TaskOutcome.SUCCESS
+ secondRunOutcome == TaskOutcome.UP_TO_DATE
+ }
+
+ def 'when generate plugin.yml - and changed plugin configuration - should update plugin.yml'() {
+ when:
+ run(RESOURCE_FACTORY)
+
+ and: "changed description"
+ buildFile << 'description = "Plugin description goes here"'
+
+ and:
+ run(RESOURCE_FACTORY)
+
+ then:
+ taskOutcome(RESOURCE_FACTORY) == TaskOutcome.SUCCESS
+
+ and: "plugin generated with new description"
+ pluginYamlFile.text == """\
+ api-version: '1.16'
+ name: test-plugin
+ version: '1.0'
+ main: com.example.testplugin.TestPlugin
+ description: Plugin description goes here
+ """.stripIndent()
+ }
+
+ void 'when generate plugin.yml - and properties configured using set'() {
+ given:
+ //language=kotlin
+ buildFile << """
+ bukkit {
+ plugin {
+ name.set("TestPlugin")
+ description.set("Test plugin description")
+ main.set("com.example.plugin.Plugin")
+ version.set("0.1")
+ apiVersion.set("1.13")
+ website.set("https://www.example.com/")
+ authors.set(listOf("OsipXD", "Contributors"))
+ }
+ }
+ """.stripIndent()
+
+ when:
+ run(RESOURCE_FACTORY)
+
+ then:
+ pluginYamlFile.text == """\
+ api-version: '1.13'
+ name: TestPlugin
+ version: '0.1'
+ main: com.example.plugin.Plugin
+ description: Test plugin description
+ authors:
+ - OsipXD
+ - Contributors
+ website: https://www.example.com/
+ """.stripIndent()
+ }
+
+ void 'when generate plugin.yml - and properties configured using assignment'() {
+ given:
+ //language=kotlin
+ buildFile << """
+ bukkit {
+ plugin {
+ name = "TestPlugin"
+ description = "Test plugin description"
+ main = "com.example.plugin.Plugin"
+ version = "0.1"
+ apiVersion = "1.13"
+ website = "https://www.example.com/"
+ authors = listOf("OsipXD", "Contributors")
+ }
+ }
+ """.stripIndent()
+
+ when:
+ run(RESOURCE_FACTORY)
+
+ then:
+ pluginYamlFile.text == """\
+ api-version: '1.13'
+ name: TestPlugin
+ version: '0.1'
+ main: com.example.plugin.Plugin
+ description: Test plugin description
+ authors:
+ - OsipXD
+ - Contributors
+ website: https://www.example.com/
+ """.stripIndent()
+ }
+
+ void 'when generate plugin.yml - should parse commands and permissions'() {
+ given:
+ pluginYamlFile.text = """\
+ depend: [Vault, ProtocolLib]
+ default-permission: not op
+ commands:
+ example:
+ description: Just a command
+ permissions:
+ example.foo:
+ description: My foo permission
+ """.stripIndent()
+
+ when:
+ run(RESOURCE_FACTORY)
+
+ then:
+ pluginYamlFile.text == """\
+ api-version: '1.16'
+ name: test-plugin
+ version: '1.0'
+ main: com.example.testplugin.TestPlugin
+ depend:
+ - Vault
+ - ProtocolLib
+ default-permission: not op
+ commands:
+ example:
+ description: Just a command
+ permissions:
+ example.foo:
+ description: My foo permission
+ """.stripIndent()
+ }
+
+ // BukkitGradle-26
+ void 'when generate plugin.yml - and there are exotic chars in source - should read it correctly'() {
+ given: "source plugin file with exotic chars"
+ pluginYamlFile.text = """\
+ commands:
+ 퀘스트:
+ description: 퀘스트 명령어 입니다.
+ """.stripIndent()
+
+ and: "default charset differs from UTF-8"
+ CharsetUtils.setDefaultCharset('CP866')
+
+ when: "run processResources"
+ try {
+ run(RESOURCE_FACTORY)
+ } finally {
+ CharsetUtils.setDefaultCharset('UTF-8')
+ }
+
+ then:
+ pluginYamlFile.text == """\
+ api-version: '1.16'
+ name: test-plugin
+ version: '1.0'
+ main: com.example.testplugin.TestPlugin
+ commands:
+ 퀘스트:
+ description: 퀘스트 명령어 입니다.
+ """.stripIndent()
+ }
+
+ void 'when generate plugin.yml - and there are fields in source - should prefer values from source'() {
+ given: "plugin.yml file with some fields"
+ pluginYamlFile.text = """\
+ name: SourceValue
+ version: 1.2
+ """.stripIndent()
+
+ when: "run processResources"
+ run(RESOURCE_FACTORY)
+
+ then: "should write plugin and keep values of the source file"
+ pluginYamlFile.text == """\
+ api-version: '1.16'
+ name: SourceValue
+ version: '1.2'
+ main: com.example.testplugin.SourceValue
+ """.stripIndent()
+ }
+
+ void 'when generate plugin.yml - and there are conflicting values'() {
+ given:
+ pluginYamlFile.text = """\
+ name: SourceValue
+ version: 1.2
+ commands:
+ source-command:
+ description: A command from source
+ permissions:
+ source.permission:
+ description: A permission from source
+ """.stripIndent()
+
+ and: "conflicting fields in build script"
+ buildFile << """
+ bukkit {
+ plugin {
+ name = "BuildscriptValue"
+ version = "1.3"
+ commands {
+ register("buildscript-command") {
+ description = "A command from build script"
+ }
+ }
+ permissions {
+ register("buildscript.permission") {
+ description = "A permission from build script"
+ }
+ }
+ }
+ }
+ """.stripIndent()
+
+ when:
+ run(RESOURCE_FACTORY)
+
+ then: "should overwrite source fields"
+ pluginYamlFile.text == """\
+ api-version: '1.16'
+ name: BuildscriptValue
+ version: '1.3'
+ main: com.example.testplugin.BuildscriptValue
+ commands:
+ buildscript-command:
+ description: A command from build script
+ source-command:
+ description: A command from source
+ permissions:
+ buildscript.permission:
+ description: A permission from build script
+ source.permission:
+ description: A permission from source
+ """.stripIndent()
+ }
+
+ void 'when generate plugin.yml - and it is already full of values - should keep existing file'() {
+ given:
+ def content = """\
+ api-version: '1.13'
+ name: TestPlugin
+ version: '0.1'
+ main: com.example.plugin.Plugin
+ description: Test plugin description
+ load: STARTUP
+ author: MainAuthor
+ authors:
+ - OsipXD
+ - Contributors
+ website: https://www.example.com/
+ depend:
+ - Dependency1
+ - Dependency2
+ softdepend:
+ - SoftDependency1
+ - SoftDependency2
+ loadbefore:
+ - LoadBefore1
+ - LoadBefore2
+ prefix: TestPrefix
+ default-permission: op
+ provides:
+ - FeatureA
+ - FeatureB
+ libraries:
+ - org.example:library:1.0
+ - com.test:util:2.0
+ commands:
+ test:
+ description: A test command
+ aliases:
+ - t
+ - tst
+ permission: test.command
+ permission-message: You need permission
+ usage: /test
+ permissions:
+ test.command:
+ description: Existing command permission
+ default: op
+ children:
+ test.command.child: true
+ folia-supported: true
+ paper-plugin-loader: custom.plugin.Loader
+ paper-skip-libraries: false
+ """.stripIndent()
+ pluginYamlFile.text = content
+
+ when:
+ run(RESOURCE_FACTORY)
+
+ then: "the file content should remain the same"
+ pluginYamlFile.text == content
+ }
+}
diff --git a/src/test/groovy/ru/endlesscode/bukkitgradle/plugin/task/MergePluginYamlSpec.groovy b/src/test/groovy/ru/endlesscode/bukkitgradle/plugin/task/MergePluginYamlSpec.groovy
deleted file mode 100644
index c674467..0000000
--- a/src/test/groovy/ru/endlesscode/bukkitgradle/plugin/task/MergePluginYamlSpec.groovy
+++ /dev/null
@@ -1,291 +0,0 @@
-package ru.endlesscode.bukkitgradle.plugin.task
-
-
-import org.gradle.testkit.runner.TaskOutcome
-import ru.endlesscode.bukkitgradle.PluginSpecification
-import ru.endlesscode.bukkitgradle.plugin.PluginConfigurationPlugin
-import ru.endlesscode.bukkitgradle.util.CharsetUtils
-
-class MergePluginYamlSpec extends PluginSpecification {
-
- private final static MERGE_PLUGIN_YAML = ':mergePluginYaml'
-
- private File sourcePluginYamlFile
- private File pluginYamlFile
-
- def setup() {
- sourcePluginYamlFile = file("src/main/resources/$PluginConfigurationPlugin.FILE_NAME")
- pluginYamlFile = file("build/tmp/mergePluginYaml/$PluginConfigurationPlugin.FILE_NAME")
-
- buildFile << """
- bukkit.apiVersion = "1.16.2"
- """.stripIndent()
- }
-
- def 'when run processResources - should also run mergePluginYaml'() {
- when:
- run(':processResources')
-
- then:
- taskOutcome(MERGE_PLUGIN_YAML) == TaskOutcome.SUCCESS
-
- and:
- taskOutcome(":parsePluginYaml") == TaskOutcome.SUCCESS
- }
-
- def 'when run processResources - and plugin.yaml generation disabled - should not run mergePluginYaml'() {
- given: "plugin generation disabled"
- buildFile << "bukkit.plugin.disablePluginYamlGeneration()"
-
- when: "run processResources"
- run(':processResources')
-
- then: "task mergePluginYaml completed successfully"
- taskOutcome(MERGE_PLUGIN_YAML) == TaskOutcome.SKIPPED
-
- and: "task mergePluginYaml completed successfully"
- taskOutcome(":parsePluginYaml") == TaskOutcome.SKIPPED
- }
-
- def 'when merge plugin.yaml - should generate default plugin.yaml successfully'() {
- when:
- run(MERGE_PLUGIN_YAML)
-
- then: "plugin file content corresponds to default config"
- pluginYamlFile.text == """
- main: "com.example.testplugin.TestPlugin"
- name: "test-plugin"
- version: "1.0"
- api-version: "1.16"
- """.stripIndent().trim()
- }
-
- def 'when merge plugin.yaml - should set api-version'(String apiVersion, String expectedResult) {
- when: "api version is $apiVersion"
- buildFile << """
- bukkit.apiVersion = "$apiVersion"
- """.stripIndent()
-
- and:
- run(MERGE_PLUGIN_YAML)
-
- then: "plugin file content corresponds to default config"
- pluginYamlFile.text == """
- main: "com.example.testplugin.TestPlugin"
- name: "test-plugin"
- version: "1.0"
- api-version: "$expectedResult"
- """.stripIndent().trim()
-
- where:
- apiVersion | expectedResult
- "1.16.5" | "1.16"
- "1.20.4" | "1.20"
- "1.20.5" | "1.20.5"
- "1.21.1" | "1.21.1"
- }
-
- def 'when merge plugin.yaml - and generate it again - should skip second task run'() {
- when:
- run(MERGE_PLUGIN_YAML)
-
- and: "run generate again"
- run(MERGE_PLUGIN_YAML)
-
- then: "the task is skipped due to up-to-date"
- taskOutcome(MERGE_PLUGIN_YAML) == TaskOutcome.UP_TO_DATE
- }
-
- def 'when merge plugin.yaml - and changed plugin configuration - should update plugin.yaml'() {
- when:
- run(MERGE_PLUGIN_YAML)
-
- and: "changed description"
- buildFile << 'description = "Plugin can has description"'
-
- and: "run the task again"
- run(MERGE_PLUGIN_YAML)
-
- then: "the task is successful"
- taskOutcome(MERGE_PLUGIN_YAML) == TaskOutcome.SUCCESS
-
- and: "plugin generated with new description"
- pluginYamlFile.text == """
- main: "com.example.testplugin.TestPlugin"
- name: "test-plugin"
- description: "Plugin can has description"
- version: "1.0"
- api-version: "1.16"
- """.stripIndent().trim()
- }
-
- void 'when merge plugin.yaml - and all properties configured - should write all lines'() {
- given: "configured all plugin properties"
- //language=kotlin
- buildFile << """
- bukkit {
- plugin {
- name.set("TestPlugin")
- description.set("Test plugin description")
- main.set("com.example.plugin.Plugin")
- version.set("0.1")
- apiVersion.set("1.13")
- url.set("https://www.example.com/")
- authors.set(listOf("OsipXD", "Contributors"))
- }
- }
- """.stripIndent()
-
- when: "run processResources"
- run(MERGE_PLUGIN_YAML)
-
- then: "should write all lines"
- pluginYamlFile.text == """
- main: "com.example.plugin.Plugin"
- name: "TestPlugin"
- description: "Test plugin description"
- version: "0.1"
- api-version: "1.13"
- authors: ["OsipXD", "Contributors"]
- website: "https://www.example.com/"
- """.stripIndent().trim()
- }
-
- void 'when merge plugin.yaml - and all properties configured with assignment - should write all lines'() {
- given: "configured all plugin properties in old way"
- //language=kotlin
- buildFile << """
- bukkit {
- plugin {
- name = "TestPlugin"
- description = "Test plugin description"
- main = "com.example.plugin.Plugin"
- version = "0.1"
- url = "https://www.example.com/"
- authors = listOf("OsipXD", "Contributors")
- }
- }
- """.stripIndent()
-
- when: "run processResources"
- run(MERGE_PLUGIN_YAML)
-
- then: "should write all lines"
- pluginYamlFile.text == """
- main: "com.example.plugin.Plugin"
- name: "TestPlugin"
- description: "Test plugin description"
- version: "0.1"
- api-version: "1.16"
- authors: ["OsipXD", "Contributors"]
- website: "https://www.example.com/"
- """.stripIndent().trim()
- }
-
- void 'when merge plugin.yaml - and there are extra fields in source - should write all lines'() {
- given: "source plugin file with extra fields"
- sourcePluginYamlFile << """
- depend: [Vault, ProtocolLib]
- commands:
- example:
- description: Just a command
- permissions:
- example.foo:
- description: My foo permission
- """.stripIndent()
-
- when: "run processResources"
- run(MERGE_PLUGIN_YAML)
-
- then: "should write plugin with the extra fields"
- pluginYamlFile.text == """
- main: "com.example.testplugin.TestPlugin"
- name: "test-plugin"
- version: "1.0"
- api-version: "1.16"
- depend: ["Vault", "ProtocolLib"]
- commands:
- "example":
- description: "Just a command"
- permissions:
- "example.foo":
- description: "My foo permission"
- """.stripIndent().trim()
- }
-
- // BukkitGradle-26
- void 'when merge plugin.yaml - and there are exotic chars in source - should read it correctly'() {
- given: "source plugin file with exotic chars"
- sourcePluginYamlFile << """
- commands:
- 퀘스트:
- description: 퀘스트 명령어 입니다.
- """.stripIndent()
-
- and: "default charset differs from UTF-8"
- CharsetUtils.setDefaultCharset('CP866')
-
- when: "run processResources"
- run(MERGE_PLUGIN_YAML)
- CharsetUtils.setDefaultCharset('UTF-8')
-
- then:
- pluginYamlFile.text == """
- main: "com.example.testplugin.TestPlugin"
- name: "test-plugin"
- version: "1.0"
- api-version: "1.16"
- commands:
- "퀘스트":
- description: "퀘스트 명령어 입니다."
- """.stripIndent().trim()
- }
-
- void 'when merge plugin.yaml - and there are fields in source - should prefer values from source'() {
- given: "source plugin file with extra fields"
- sourcePluginYamlFile << """
- name: SourceValue
- version: 1.2
- """.stripIndent()
-
- when: "run processResources"
- run(MERGE_PLUGIN_YAML)
-
- then: "should write plugin and prefer source fields"
- pluginYamlFile.text == """
- main: "com.example.testplugin.SourceValue"
- name: "SourceValue"
- version: "1.2"
- api-version: "1.16"
- """.stripIndent().trim()
- }
-
- void 'when merge plugin.yaml - and there are conflicting fields in source and in build script - should prefer values from build script'() {
- given: "source plugin.yaml file with extra fields"
- sourcePluginYamlFile << """
- name: SourceValue
- version: 1.2
- """.stripIndent()
-
- and: "conflicting fields in build script"
- buildFile << """
- bukkit {
- plugin {
- name.set("BuildscriptValue")
- version.set("1.3")
- }
- }
- """.stripIndent()
-
- when:
- run(MERGE_PLUGIN_YAML)
-
- then: "should overwrite source fields"
- pluginYamlFile.text == """
- main: "com.example.testplugin.BuildscriptValue"
- name: "BuildscriptValue"
- version: "1.3"
- api-version: "1.16"
- """.stripIndent().trim()
- }
-}