Plugin publishing via gradle plugin

This commit is contained in:
Him188 2020-11-29 00:15:03 +08:00
parent 08c61dee0e
commit 9a2ea32e93
4 changed files with 194 additions and 49 deletions

View File

@ -0,0 +1,18 @@
package net.mamoe.mirai.console.gradle
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.api.tasks.CacheableTask
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import java.io.File
@CacheableTask
public open class BuildMiraiPluginTask : ShadowJar() {
internal var targetField: KotlinTarget? = null
public val target: KotlinTarget get() = targetField!!
/**
* ShadowJar 打包结果
*/
public val output: File get() = outputs.files.singleFile
}

View File

@ -13,8 +13,10 @@ package net.mamoe.mirai.console.gradle
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import com.jfrog.bintray.gradle.BintrayExtension
import com.jfrog.bintray.gradle.BintrayPlugin
import org.gradle.api.JavaVersion
import org.gradle.api.XmlProvider
import org.gradle.api.plugins.PluginContainer
import org.gradle.api.publish.maven.MavenPublication
/**
@ -126,31 +128,44 @@ public open class MiraiConsoleExtension {
/**
* Bintray 插件成品 JAR 发布 配置.
*
* @see Publishing
* @see PluginPublishing
* @since 1.1.0
*/
public val publishing: Publishing = Publishing()
public val publishing: PluginPublishing = PluginPublishing()
/**
* 控制自动配置 Bintray 发布
* @since 1.1.0
*/
public var publishingEnabled: Boolean = true
/**
* Bintray 插件成品 JAR 发布 配置.
* 控制自动配置 Bintray 发布. 默认为 `false`, 表示不自动配置发布.
*
* 开启后将会:
* - 创建名为 "mavenJava" [MavenPublication]
* - [应用][PluginContainer.apply] [BintrayPlugin], 配置 Bintray 相关参数
* - 创建 task "publishPlugin"
*
* @see [Publishing]
* @since 1.1.0
*/
public inline fun publishing(block: Publishing.() -> Unit): Unit = publishing.run(block)
public var publishingEnabled: Boolean = false
/**
* 开启自动配置 Bintray 插件成品 JAR 发布, 并以 [configure] 配置 [PluginPublishing].
*
* @see [PluginPublishing]
* @see publishingEnabled
* @since 1.1.0
*/
public fun disablePublishing() {
publishingEnabled = false
public inline fun publishing(crossinline configure: PluginPublishing.() -> Unit) {
publishingEnabled = true
publishing.run(configure)
}
/**
* 开启自动配置 Bintray 插件成品 JAR 发布.
*
* @see [PluginPublishing]
* @see publishingEnabled
* @since 1.1.0
*/
public fun publishing() {
publishingEnabled = true
}
/**
@ -166,36 +181,37 @@ public open class MiraiConsoleExtension {
* 4. [System.getenv] "PROP"
*
* @see publishing
* @see publishingEnabled
* @since 1.1.0
*/
public class Publishing internal constructor() {
public class PluginPublishing internal constructor() {
///////////////////////////////////////////////////////////////////////////
// Required arguments
///////////////////////////////////////////////////////////////////////////
/**
* Bintray 账户名. 必须.
* 若为 `null`, 将会以 [Publishing] 中描述的步骤获取 "bintray.user"
* 若为 `null`, 将会以 [PluginPublishing] 中描述的步骤获取 "bintray.user"
*
* @see [Publishing]
* @see [PluginPublishing]
*/
public var user: String? = null
/**
* Bintray 账户 key. 必须.
* 若为 `null`, 将会以 [Publishing] 中描述的步骤获取 "bintray.key"
* 若为 `null`, 将会以 [PluginPublishing] 中描述的步骤获取 "bintray.key"
*/
public var key: String? = null
/**
* 目标仓库名称. 必须.
* 若为 `null`, 将会以 [Publishing] 中描述的步骤获取 "bintray.repo"
* 若为 `null`, 将会以 [PluginPublishing] 中描述的步骤获取 "bintray.repo"
*/
public var repo: String? = null
/**
* 目标仓库名称. 必须.
* 若为 `null`, 将会以 [Publishing] 中描述的步骤获取 "bintray.package"
* 若为 `null`, 将会以 [PluginPublishing] 中描述的步骤获取 "bintray.package"
*/
public var packageName: String? = null
@ -227,11 +243,16 @@ public open class MiraiConsoleExtension {
*/
public var version: String? = null
/**
* 发布的描述, 默认为 `project.description`
*/
public var description: String? = null
// Bintray
/**
* Bintray organization . 可选.
* 若为 `null`, 将会以 [Publishing] 中描述的步骤获取 "bintray.org".
* 若为 `null`, 将会以 [PluginPublishing] 中描述的步骤获取 "bintray.org".
* 仍然无法获取时发布到 [user] 账号下的仓库 [repo], 否则发布到指定 [org] 下的仓库 [repo].
*/
public var org: String? = null
@ -256,29 +277,29 @@ public open class MiraiConsoleExtension {
/**
* 自定义配置 [BintrayExtension]覆盖
*/
public fun bintray(config: BintrayExtension.() -> Unit) {
bintrayConfigs.add(config)
public fun bintray(configure: BintrayExtension.() -> Unit) {
bintrayConfigs.add(configure)
}
/**
* 自定义配置 [BintrayExtension.PackageConfig]
*/
public fun packageConfig(config: BintrayExtension.PackageConfig.() -> Unit) {
bintrayPackageConfigConfigs.add(config)
public fun packageConfig(configure: BintrayExtension.PackageConfig.() -> Unit) {
bintrayPackageConfigConfigs.add(configure)
}
/**
* 自定义配置 maven pom.xml [XmlProvider]
*/
public fun mavenPom(config: XmlProvider.() -> Unit) {
mavenPomConfigs.add(config)
public fun mavenPom(configure: XmlProvider.() -> Unit) {
mavenPomConfigs.add(configure)
}
/**
* 自定义配置 [MavenPublication]
*/
public fun mavenPublication(config: MavenPublication.() -> Unit) {
mavenPublicationConfigs.add(config)
public fun mavenPublication(configure: MavenPublication.() -> Unit) {
mavenPublicationConfigs.add(configure)
}
}
}

View File

@ -13,7 +13,7 @@
package net.mamoe.mirai.console.gradle
import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import com.jfrog.bintray.gradle.BintrayPlugin
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPlugin
@ -101,18 +101,18 @@ public class MiraiConsoleGradlePlugin : Plugin<Project> {
tasks.findByName("shadowJar")?.enabled = false
fun registerBuildPluginTask(target: KotlinTarget, isSinglePlatform: Boolean) {
tasks.create(if (isSinglePlatform) "buildPlugin" else "buildPlugin${target.name.capitalize()}", ShadowJar::class.java).apply shadow@{
fun registerBuildPluginTask(target: KotlinTarget, isSingleTarget: Boolean) {
tasks.create("buildPlugin".wrapNameWithPlatform(target, isSingleTarget), BuildMiraiPluginTask::class.java).apply shadow@{
group = "mirai"
targetField = target
archiveExtension.set("mirai.jar")
val compilations = target.compilations.filter { it.name == MAIN_COMPILATION_NAME }
compilations.forEach {
dependsOn(it.compileKotlinTask)
from(it.output)
for (allKotlinSourceSet in it.allKotlinSourceSets) {
from(allKotlinSourceSet.resources)
}
from(it.output.allOutputs)
}
from(project.configurations.getByName("runtimeClasspath").copyRecursive { dependency ->
@ -142,18 +142,20 @@ public class MiraiConsoleGradlePlugin : Plugin<Project> {
}
override fun apply(target: Project): Unit = with(target) {
target.extensions.create("mirai", MiraiConsoleExtension::class.java)
extensions.create("mirai", MiraiConsoleExtension::class.java)
target.plugins.apply(JavaPlugin::class.java)
target.plugins.apply(ShadowPlugin::class.java)
target.repositories.maven { it.setUrl(BINTRAY_REPOSITORY_URL) }
plugins.apply(JavaPlugin::class.java)
plugins.apply("org.gradle.maven-publish")
plugins.apply("org.gradle.maven")
plugins.apply(ShadowPlugin::class.java)
plugins.apply(BintrayPlugin::class.java)
repositories.maven { it.setUrl(BINTRAY_REPOSITORY_URL) }
afterEvaluate {
configureCompileTarget()
kotlinTargets.forEach { configureTarget(it) }
registerBuildPluginTasks()
registerPublishPluginTask()
configurePublishing()
}
}
}
@ -171,4 +173,7 @@ internal val Project.kotlinTargets: Collection<KotlinTarget>
is KotlinSingleTargetExtension -> listOf(kotlinExtension.target)
else -> error("[MiraiConsole] Internal error: kotlinExtension is neither KotlinMultiplatformExtension nor KotlinSingleTargetExtension")
}
}
}
internal val Project.kotlinJvmOrAndroidTargets: Collection<KotlinTarget>
get() = kotlinTargets.filter { it.platformType == KotlinPlatformType.jvm || it.platformType == KotlinPlatformType.androidJvm }

View File

@ -9,13 +9,19 @@
package net.mamoe.mirai.console.gradle
import com.google.gson.Gson
import com.jfrog.bintray.gradle.tasks.BintrayUploadTask
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.tasks.TaskContainer
import org.gradle.api.tasks.bundling.Jar
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.getValue
import org.gradle.kotlin.dsl.provideDelegate
import org.gradle.kotlin.dsl.registering
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import java.io.File
private val Project.selfAndParentProjects: Sequence<Project>
@ -29,17 +35,105 @@ private fun Project.findPropertySmart(propName: String): String? {
}
private fun Project.findPropertySmartOrFail(propName: String): String {
return findPropertySmart(propName) ?: error("[Mirai Console] Cannot find property for publication: $propName. Please check your 'mirai' configuration.")
return findPropertySmart(propName)
?: error("[Mirai Console] Cannot find property for publication: '$propName'. Please check your 'mirai' configuration.")
}
internal fun Project.registerPublishPluginTask() {
internal fun Project.configurePublishing() {
if (!miraiExtension.publishingEnabled) return
val isSingleTarget = kotlinJvmOrAndroidTargets.size == 1
kotlinJvmOrAndroidTargets.forEach {
registerPublishPluginTasks(it, isSingleTarget)
registerMavenPublications(it, isSingleTarget)
}
registerBintrayPublish()
}
private inline fun <reified T : Task> TaskContainer.getSingleTask(): T = filterIsInstance<T>().single()
private fun Project.registerPublishPluginTasks() {
val isSingleTarget = kotlinJvmOrAndroidTargets.size == 1
kotlinJvmOrAndroidTargets.forEach { registerPublishPluginTasks(it, isSingleTarget) }
}
// effectively public
internal data class PluginMetadata(
val groupId: String,
val artifactId: String,
val version: String,
val description: String?,
val dependencies: List<String>
)
internal fun String.wrapNameWithPlatform(target: KotlinTarget, isSingleTarget: Boolean): String {
return if (isSingleTarget) this else "$this${target.name.capitalize()}"
}
private fun Project.registerPublishPluginTasks(target: KotlinTarget, isSingleTarget: Boolean) {
val generateMetadataTask =
tasks.register("generatePluginMetadata".wrapNameWithPlatform(target, isSingleTarget)).get().apply {
group = "mirai"
val metadataFile =
project.buildDir.resolve("mirai").resolve(if (isSingleTarget) "mirai-plugin.metadata" else "mirai-plugin-${target.name}.metadata")
outputs.file(metadataFile)
doLast {
val mirai = miraiExtension
val output = outputs.files.singleFile
output.parentFile.mkdir()
val dependencies = configurations[target.compilations["main"].apiConfigurationName].allDependencies.map {
"${it.group}:${it.name}:${it.version}"
}
val json = Gson().toJson(PluginMetadata(
groupId = mirai.publishing.groupId ?: project.group.toString(),
artifactId = mirai.publishing.artifactId ?: project.name,
version = mirai.publishing.version ?: project.version.toString(),
description = mirai.publishing.description ?: project.description,
dependencies = dependencies
))
logger.info("Generated mirai plugin metadata json: $json")
output.writeText(json)
}
}
val bintrayUpload = tasks.getByName(BintrayUploadTask.getTASK_NAME()).dependsOn(
"buildPlugin".wrapNameWithPlatform(target, isSingleTarget),
generateMetadataTask,
// "shadowJar",
tasks.filterIsInstance<BuildMiraiPluginTask>().single { it.target == target }
)
tasks.register("publishPlugin".wrapNameWithPlatform(target, isSingleTarget)).get().apply {
group = "mirai"
dependsOn(bintrayUpload)
}
}
internal inline fun File.renamed(block: File.(nameWithoutExtension: String) -> String): File = this.resolveSibling(block(this, nameWithoutExtension))
private fun Project.registerBintrayPublish() {
val mirai = miraiExtension
bintray {
user = mirai.publishing.user ?: findPropertySmartOrFail("bintray.user")
key = mirai.publishing.key ?: findPropertySmartOrFail("bintray.key")
setPublications("mavenJava")
val targets = kotlinJvmOrAndroidTargets
if (targets.size == 1) {
setPublications("mavenJava")
} else {
setPublications(*targets.map { "mavenJava".wrapNameWithPlatform(it, false) }.toTypedArray())
}
setConfigurations("archives")
publish = mirai.publishing.publish
@ -49,12 +143,17 @@ internal fun Project.registerPublishPluginTask() {
repo = mirai.publishing.repo ?: findPropertySmartOrFail("bintray.repo")
name = mirai.publishing.packageName ?: findPropertySmartOrFail("bintray.package")
userOrg = mirai.publishing.org ?: findPropertySmart("bintray.org")
desc = mirai.publishing.description ?: project.description
mirai.publishing.bintrayPackageConfigConfigs.forEach { it.invoke(this) }
}
mirai.publishing.bintrayConfigs.forEach { it.invoke(this) }
}
}
private fun Project.registerMavenPublications(target: KotlinTarget, isSingleTarget: Boolean) {
val mirai = miraiExtension
@Suppress("DEPRECATION")
val sourcesJar by tasks.registering(Jar::class) {
@ -70,7 +169,7 @@ internal fun Project.registerPublishPluginTask() {
url = uri("$buildDir/repo")
}
}*/
publications.register("mavenJava", MavenPublication::class.java) { publication ->
publications.register("mavenJava".wrapNameWithPlatform(target, isSingleTarget), MavenPublication::class.java) { publication ->
with(publication) {
from(components["java"])
@ -89,9 +188,11 @@ internal fun Project.registerPublishPluginTask() {
}
artifact(sourcesJar.get())
// TODO: 2020/11/28 -miraip metadata artifact
// TODO: 2020/11/28 -all shadowed artifact
artifact(tasks.filterIsInstance<BuildMiraiPluginTask>().single { it.target == target })
artifact(mapOf(
"source" to tasks.getByName("generatePluginMetadata".wrapNameWithPlatform(target, isSingleTarget)).outputs.files.singleFile,
"extension" to "metadata"
))
mirai.publishing.mavenPublicationConfigs.forEach { it.invoke(this) }
}