[build] Fix shadow task dependencies and check-publishing actions

This commit is contained in:
Him188
2022-11-20 12:28:04 +00:00
parent c9dd92c694
commit 4c8a18edb7
6 changed files with 115 additions and 30 deletions

View File

@@ -78,7 +78,7 @@ jobs:
- name: Build and Publish Local Artifacts - name: Build and Publish Local Artifacts
if: ${{ env.enableLocalPublishingTest == 'true' }} if: ${{ env.enableLocalPublishingTest == 'true' }}
run: ./gradlew :mirai-deps-test:publishMiraiArtifactsToMavenLocal ${{ env.gradleArgs }} "-Dmirai.build.project.version=2.99.0-deps-test" run: ./gradlew :mirai-deps-test:publishMiraiLocalArtifacts ${{ env.gradleArgs }} "-Dmirai.build.project.version=2.99.0-deps-test"
- name: Check Publication - name: Check Publication
if: ${{ env.enableLocalPublishingTest == 'true' }} if: ${{ env.enableLocalPublishingTest == 'true' }}
@@ -204,7 +204,7 @@ jobs:
- name: Build and Publish Local Artifacts - name: Build and Publish Local Artifacts
if: ${{ env.enableLocalPublishingTest == 'true' }} if: ${{ env.enableLocalPublishingTest == 'true' }}
run: ./gradlew :mirai-deps-test:publishMiraiArtifactsToMavenLocal ${{ env.gradleArgs }} "-Dmirai.build.project.version=2.99.0-deps-test" run: ./gradlew :mirai-deps-test:publishMiraiLocalArtifacts ${{ env.gradleArgs }} "-Dmirai.build.project.version=2.99.0-deps-test"
- name: Check Publication - name: Check Publication
if: ${{ env.enableLocalPublishingTest == 'true' }} if: ${{ env.enableLocalPublishingTest == 'true' }}

View File

@@ -87,6 +87,9 @@ allprojects {
substituteDependenciesUsingExpectedVersion() substituteDependenciesUsingExpectedVersion()
} }
} }
afterEvaluate {
configureShadowDependenciesForPublishing()
}
subprojects { subprojects {
afterEvaluate { afterEvaluate {

View File

@@ -86,14 +86,17 @@ enum class HostArch {
/// eg. "a;b;!other" means to disable all targets but a or b /// eg. "a;b;!other" means to disable all targets but a or b
val ENABLED_TARGETS by lazy { val ENABLED_TARGETS by lazy {
val targets = System.getProperty( val targets = getMiraiTargetFromGradle() // enable all by default
"mirai.target"
) ?: rootProject.getLocalProperty("projects.mirai-core.targets")
?: "others" // enable all by default
targets.split(';').toSet() targets.split(';').toSet()
} }
fun getMiraiTargetFromGradle() =
System.getProperty("mirai.target")
?: System.getenv("mirai.target")
?: rootProject.getLocalProperty("projects.mirai-core.targets")
?: "others"
fun isTargetEnabled(name: String): Boolean { fun isTargetEnabled(name: String): Boolean {
val isNative = name in POSSIBLE_NATIVE_TARGETS val isNative = name in POSSIBLE_NATIVE_TARGETS
return when { return when {

View File

@@ -13,6 +13,7 @@ import com.google.gson.GsonBuilder
import org.gradle.api.GradleException import org.gradle.api.GradleException
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.Task import org.gradle.api.Task
import org.gradle.api.execution.TaskExecutionGraph
import org.gradle.api.publish.tasks.GenerateModuleMetadata import org.gradle.api.publish.tasks.GenerateModuleMetadata
import org.gradle.kotlin.dsl.create import org.gradle.kotlin.dsl.create
import org.gradle.kotlin.dsl.get import org.gradle.kotlin.dsl.get
@@ -29,20 +30,68 @@ fun Project.configureMppShadow() {
it.platformType == org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.jvm it.platformType == org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.jvm
&& (it.attributes.getAttribute(MIRAI_PLATFORM_INTERMEDIATE) != true) && (it.attributes.getAttribute(MIRAI_PLATFORM_INTERMEDIATE) != true)
}) { }) {
configureRelocationForTarget(project) configureRelocationForMppTarget(project)
registerRegularShadowTask(this, mapTaskNameForMultipleTargets = true) registerRegularShadowTask(this, mapTaskNameForMultipleTargets = true)
} }
} }
/**
* 配置 `publish` 和 `shadow` 相关依赖. 对于在本次构建的请求的任务及其直接或间接依赖, 以以下顺序执行:
*
* 1. 执行全部 `jar` 任务
* 2. 执行全部 `relocate` 任务
* 3. 执行全部 `publish` 任务
*
* 这是必要的因为 relocate 任务会覆盖 jar 任务的输出, 而在多模块并行编译时, Kotlin 编译器会依赖 jar 任务的输出. 如果在编译同时修改 JAR 文件, 就会导致 `ZipException`.
*
* 这也会让 publish 集中执行, Maven Central 不容易出问题.
*/
fun Project.configureShadowDependenciesForPublishing() {
check(this.rootProject === this) {
"configureShadowDependenciesForPublishing can only be used on root project."
}
gradle.projectsEvaluated {
// Tasks requested to run in this build
val allTasks = rootProject.allprojects.asSequence().flatMap { it.tasks }
val publishTasks = allTasks.filter { it.name.contains("publish", ignoreCase = true) }
val relocateTasks = allTasks.filter { it.name.contains("relocate", ignoreCase = true) }
val jarTasks = allTasks.filter { it.name.contains("jar", ignoreCase = true) }
val compileKotlinTasks = allTasks.filter { it.name.contains("compileKotlin", ignoreCase = true) }
val compileTestKotlinTasks = allTasks.filter { it.name.contains("compileTestKotlin", ignoreCase = true) }
relocateTasks.dependsOn(compileKotlinTasks.toList())
relocateTasks.dependsOn(compileTestKotlinTasks.toList())
relocateTasks.dependsOn(jarTasks.toList())
publishTasks.dependsOn(relocateTasks.toList())
}
}
val TaskExecutionGraph.hierarchicalTasks: Sequence<Task>
get() = sequence {
suspend fun SequenceScope<Task>.addTask(task: Task) {
yield(task)
for (dependency in getDependencies(task)) {
addTask(dependency)
}
}
for (task in allTasks) {
addTask(task)
}
}
/** /**
* Relocate some dependencies for `.jar` * Relocate some dependencies for `.jar`
* @see RelocationNotes * @see RelocationNotes
*/ */
private fun KotlinTarget.configureRelocationForTarget(project: Project) = project.run { private fun KotlinTarget.configureRelocationForMppTarget(project: Project) = project.run {
val configuration = project.configurations.findByName(SHADOW_RELOCATION_CONFIGURATION_NAME) val configuration = project.configurations.findByName(SHADOW_RELOCATION_CONFIGURATION_NAME)
// e.g. relocateJvmDependencies // e.g. relocateJvmDependencies
// do not change task name. see `configureShadowDependenciesForPublishing`
val relocateDependencies = tasks.create("relocate${targetName.titlecase()}Dependencies", ShadowJar::class) { val relocateDependencies = tasks.create("relocate${targetName.titlecase()}Dependencies", ShadowJar::class) {
group = "mirai" group = "mirai"
description = "Relocate dependencies to internal package" description = "Relocate dependencies to internal package"
@@ -67,15 +116,13 @@ private fun KotlinTarget.configureRelocationForTarget(project: Project) = projec
} }
} }
// Relocate before packing Jar. Projects that depends on this project actually (explicitly or implicitly) depends on the Jar.
tasks.getByName("${targetName}Jar").dependsOn(relocateDependencies)
// We will modify Kotlin metadata, so do generate metadata before relocation // We will modify Kotlin metadata, so do generate metadata before relocation
val generateMetadataTask = val generateMetadataTask =
tasks.getByName("generateMetadataFileFor${targetName.capitalize()}Publication") as GenerateModuleMetadata tasks.getByName("generateMetadataFileFor${targetName.capitalize()}Publication") as GenerateModuleMetadata
val patchMetadataTask = tasks.create("patchMetadataFileFor${targetName.capitalize()}RelocatedPublication") { val patchMetadataTask = tasks.create("patchMetadataFileFor${targetName.capitalize()}RelocatedPublication") {
dependsOn(generateMetadataTask) dependsOn(generateMetadataTask)
dependsOn(relocateDependencies)
// remove dependencies in Kotlin module metadata // remove dependencies in Kotlin module metadata
doLast { doLast {
@@ -157,23 +204,15 @@ private fun KotlinTarget.configureRelocationForTarget(project: Project) = projec
} }
private fun Sequence<Task>.dependsOn( private fun Sequence<Task>.dependsOn(
relocateDependencies: ShadowJar, task: Task,
kotlinTarget: KotlinTarget, ) {
): Int { return forEach { it.dependsOn(task) }
return onEach { relocateDependencies.dependsOn(it) }
.count().also {
check(it > 0) { "[Shadow Relocation] Expected at least one task task matched for target ${kotlinTarget.targetName}." }
}
} }
private fun Sequence<Task>.mustRunAfter( private fun Sequence<Task>.dependsOn(
relocateDependencies: ShadowJar, tasks: Iterable<Task>,
kotlinTarget: KotlinTarget, ) {
): Int { return forEach { it.dependsOn(tasks) }
return onEach { relocateDependencies.mustRunAfter(it) }
.count().also {
check(it > 0) { "[Shadow Relocation] Expected at least one task task matched for target ${kotlinTarget.targetName}." }
}
} }
private fun Project.registerRegularShadowTask(target: KotlinTarget, mapTaskNameForMultipleTargets: Boolean): ShadowJar { private fun Project.registerRegularShadowTask(target: KotlinTarget, mapTaskNameForMultipleTargets: Boolean): ShadowJar {

View File

@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler
object Versions { object Versions {
val project = System.getenv("mirai.build.project.version")?.takeIf { it.isNotBlank() } val project = System.getenv("mirai.build.project.version")?.takeIf { it.isNotBlank() }
?: System.getProperty("mirai.build.project.version")?.takeIf { it.isNotBlank() } ?: System.getProperty("mirai.build.project.version")?.takeIf { it.isNotBlank() }
?: /*PROJECT_VERSION_START*/"2.14.0-dev-shadow-1"/*PROJECT_VERSION_END*/ ?: /*PROJECT_VERSION_START*/"2.14.0-dev-shadow-6"/*PROJECT_VERSION_END*/
val core = project val core = project
val console = project val console = project

View File

@@ -86,19 +86,59 @@ fun generateBuildConfig() {
} }
} }
tasks.register("publishMiraiLocalArtifacts", Exec::class) { // keep this property for Search Everywhere
val publishMiraiLocalArtifacts = tasks.register("publishMiraiLocalArtifacts", Exec::class) {
group = "mirai" group = "mirai"
description = "Starts a child process to publish v2.99.0-deps-test artifacts to MavenLocal" description = "Starts a child process to publish v2.99.0-deps-test artifacts to MavenLocal"
workingDir(rootProject.projectDir) workingDir(rootProject.projectDir)
// The following code configures the new Gradle instance to inheriting configuration.
// This is important especially for "mirai.target" settings
// — On CI machines we didn't configure them to cross-compilation.
// Note that IntelliJ listener is also inherited, so you will see normal execution feedbacks in your IDE 'Run' view.
environment(System.getenv())
environment("mirai.build.project.version", "2.99.0-deps-test") environment("mirai.build.project.version", "2.99.0-deps-test")
environment("mirai.target", getMiraiTargetFromGradle())
val projectProperties =
// gradle.startParameter.projectProperties
mapOf<String, String>()
.toMutableMap().apply {
put("kotlin.compiler.execution.strategy", "in-process")
}
.map { "-P${it.key}=${it.value}" }
.toTypedArray()
val allowedProperties = arrayOf("org.gradle.parallel")
val systemProperties =
// gradle.startParameter.systemPropertiesArgs
gradle.startParameter.systemPropertiesArgs
.filter { it.key in allowedProperties }
.map { "-D${it.key}=${it.value}" }
.toTypedArray()
commandLine( commandLine(
"./gradlew", "./gradlew",
publishMiraiArtifactsToMavenLocal.name, publishMiraiArtifactsToMavenLocal.name,
"--no-daemon", "--no-daemon",
"--stacktrace", "--stacktrace",
"-Pkotlin.compiler.execution.strategy=in-process" "--scan",
) *projectProperties,
*systemProperties,
) // ignore other Gradle args
doFirst {
// TODO: 2022/11/22 fix tips
logger.info(
"[publishMiraiLocalArtifacts] Starting a Gradle daemon to run requested publishing tasks. " +
"Your system environment, JVM properties, and Gradle properties are inherited, " +
"but note that any other Gradle arguments are IGNORED!"
)
logger.info("[publishMiraiLocalArtifacts] Oh, and don't worry, the daemon will be stopped after the task finishes so it won't waste your memory!")
}
standardOutput = System.out standardOutput = System.out
errorOutput = System.err errorOutput = System.err
} }