diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 88b7be217..eb17032a8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -280,6 +280,9 @@ jobs: - name: "Assemble" run: ./gradlew assemble ${{ env.gradleArgs }} + - name: Publish Local Artifacts + run: ./gradlew :mirai-deps-test:publishMiraiLocalArtifacts ${{ env.gradleArgs }} + - name: "Check" run: ./gradlew check ${{ env.gradleArgs }} @@ -402,4 +405,10 @@ jobs: run: ./gradlew :mirai-core-api:${{ matrix.targetName }}Test ${{ env.gradleArgs }} - name: "Test mirai-core for ${{ matrix.os }}" - run: ./gradlew :mirai-core:${{ matrix.targetName }}Test ${{ env.gradleArgs }} \ No newline at end of file + run: ./gradlew :mirai-core:${{ matrix.targetName }}Test ${{ env.gradleArgs }} + + - name: Publish Local Artifacts + run: ./gradlew :mirai-deps-test:publishMiraiLocalArtifacts ${{ env.gradleArgs }} + + - name: Check Publication + run: ./gradlew :mirai-deps-test:check ${{ env.gradleArgs }} diff --git a/.github/workflows/snapshots.yml b/.github/workflows/snapshots.yml index b043ecabc..a2cfa87bd 100644 --- a/.github/workflows/snapshots.yml +++ b/.github/workflows/snapshots.yml @@ -37,9 +37,13 @@ jobs: - name: Assemble run: ./gradlew assemble --scan + - name: Publish Local Artifacts + run: > + ./gradlew :mirai-deps-test:publishMiraiLocalArtifacts --scan + - name: Check run: > - ./gradlew check --scan --no-parallel + ./gradlew check --scan -Dmirai.network.show.all.components=true -Dkotlinx.coroutines.debug=on -Dmirai.network.show.packet.details=true diff --git a/build.gradle.kts b/build.gradle.kts index 635595be6..7f7bb20f1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,8 +12,6 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.base.DokkaBaseConfiguration -import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension -import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import java.time.LocalDateTime buildscript { @@ -35,12 +33,13 @@ buildscript { } plugins { - kotlin("jvm") // version Versions.kotlinCompiler - kotlin("plugin.serialization") version Versions.kotlinCompiler + kotlin("jvm") apply false // version Versions.kotlinCompiler + kotlin("plugin.serialization") version Versions.kotlinCompiler apply false id("com.google.osdetector") id("org.jetbrains.dokka") version Versions.dokka id("me.him188.kotlin-jvm-blocking-bridge") version Versions.blockingBridge - id("me.him188.kotlin-dynamic-delegation") version Versions.dynamicDelegation + id("me.him188.kotlin-dynamic-delegation") version Versions.dynamicDelegation apply false + id("me.him188.maven-central-publish") version Versions.mavenCentralPublish apply false id("com.gradle.plugin-publish") version "1.0.0-rc-3" apply false id("org.jetbrains.kotlinx.binary-compatibility-validator") version Versions.binaryValidator apply false } @@ -179,43 +178,3 @@ fun Project.configureDokka() { } } } - -fun Project.configureMppShadow() { - val kotlin = - runCatching { - - (this as ExtensionAware).extensions.getByName("kotlin") as? KotlinMultiplatformExtension - }.getOrNull() ?: return - - if (project.configurations.findByName("jvmRuntimeClasspath") != null) { - val shadowJvmJar by tasks.creating(ShadowJar::class) sd@{ - group = "mirai" - archiveClassifier.set("-all") - - val compilations = - kotlin.targets.filter { it.platformType == KotlinPlatformType.jvm } - .map { it.compilations["main"] } - - compilations.forEach { - dependsOn(it.compileKotlinTask) - from(it.output) - } - - from(project.configurations.findByName("jvmRuntimeClasspath")) - - this.exclude { file -> - file.name.endsWith(".sf", ignoreCase = true) - } - - /* - this.manifest { - this.attributes( - "Manifest-Version" to 1, - "Implementation-Vendor" to "Mamoe Technologies", - "Implementation-Title" to this.name.toString(), - "Implementation-Version" to this.version.toString() - ) - }*/ - } - } -} diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 6fbc735dc..db79eef43 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -57,6 +57,7 @@ dependencies { api(asm("tree")) api(asm("util")) api(asm("commons")) + api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2") api("gradle.plugin.com.google.gradle:osdetector-gradle-plugin:1.7.0") diff --git a/buildSrc/src/main/kotlin/HmppConfigure.kt b/buildSrc/src/main/kotlin/HmppConfigure.kt index 104b7bda4..ee3affa52 100644 --- a/buildSrc/src/main/kotlin/HmppConfigure.kt +++ b/buildSrc/src/main/kotlin/HmppConfigure.kt @@ -25,7 +25,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType import org.jetbrains.kotlin.gradle.plugin.mpp.TestExecutable import java.io.File -private val miraiPlatform = Attribute.of( +val MIRAI_PLATFORM_ATTRIBUTE = Attribute.of( "net.mamoe.mirai.platform", String::class.java ) @@ -140,7 +140,7 @@ fun Project.configureJvmTargetsHierarchical() { this.compileKotlinTask.enabled = false // IDE complain } attributes.attribute(KotlinPlatformType.attribute, KotlinPlatformType.common) // magic - attributes.attribute(miraiPlatform, "jvmBase") // avoid resolution + attributes.attribute(MIRAI_PLATFORM_ATTRIBUTE, "jvmBase") // avoid resolution } } @@ -160,7 +160,7 @@ fun Project.configureJvmTargetsHierarchical() { jvm("android") { attributes.attribute(KotlinPlatformType.attribute, KotlinPlatformType.androidJvm) if (IDEA_ACTIVE) { - attributes.attribute(miraiPlatform, "android") // avoid resolution + attributes.attribute(MIRAI_PLATFORM_ATTRIBUTE, "android") // avoid resolution } } val androidMain by sourceSets.getting diff --git a/buildSrc/src/main/kotlin/Mpp.kt b/buildSrc/src/main/kotlin/Mpp.kt index 94d8e0860..4d3724a1e 100644 --- a/buildSrc/src/main/kotlin/Mpp.kt +++ b/buildSrc/src/main/kotlin/Mpp.kt @@ -1,10 +1,10 @@ /* - * Copyright 2019-2021 Mamoe Technologies and contributors. + * Copyright 2019-2022 Mamoe Technologies and contributors. * - * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. - * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. * - * https://github.com/mamoe/mirai/blob/master/LICENSE + * https://github.com/mamoe/mirai/blob/dev/LICENSE */ import org.gradle.api.NamedDomainObjectCollection @@ -13,17 +13,10 @@ import org.gradle.api.Project import org.gradle.api.artifacts.DependencySubstitutions import org.gradle.api.artifacts.ResolutionStrategy import org.gradle.api.artifacts.component.ComponentSelector +import org.gradle.api.plugins.ExtensionAware +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import java.util.* -/* - * Copyright 2020 Mamoe Technologies and contributors. - * - * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. - * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. - * - * https://github.com/mamoe/mirai/blob/master/LICENSE - */ - private object ProjectAndroidSdkAvailability { val map: MutableMap = mutableMapOf() @@ -117,3 +110,10 @@ fun ResolutionStrategy.substituteDependencies(action: ResolutionStrategyDsl.() - action(ResolutionStrategyDsl(this)) } } + + +val Project.kotlinMpp + get() = runCatching { + (this as ExtensionAware).extensions.getByName("kotlin") as? KotlinMultiplatformExtension + }.getOrNull() + diff --git a/buildSrc/src/main/kotlin/MppPublishing.kt b/buildSrc/src/main/kotlin/MppPublishing.kt index 21ca3aa8c..77773f8c4 100644 --- a/buildSrc/src/main/kotlin/MppPublishing.kt +++ b/buildSrc/src/main/kotlin/MppPublishing.kt @@ -11,6 +11,7 @@ import org.gradle.api.Project import org.gradle.api.XmlProvider import org.gradle.api.publish.maven.MavenArtifact import org.gradle.api.publish.maven.MavenPublication +import org.gradle.api.tasks.TaskProvider import org.gradle.jvm.tasks.Jar import org.gradle.kotlin.dsl.get import org.gradle.kotlin.dsl.register @@ -43,30 +44,39 @@ fun Project.configureMppPublishing() { publishing { logPublishing("Publications: ${publications.joinToString { it.name }}") - publications.filterIsInstance().forEach { publication -> - // Maven Central always require javadoc.jar - publication.artifact(stubJavadoc) + val (nonJvmPublications, jvmPublications) = publications.filterIsInstance() + .partition { publication -> tasks.findByName("relocate${publication.name.titlecase()}Dependencies") == null } - publication.setupPom(project) - - logPublishing(publication.name) - when (val type = publication.name) { - "kotlinMultiplatform" -> { - publication.artifactId = project.name - - // publishPlatformArtifactsInRootModule(publications.getByName("jvm") as MavenPublication) - - // TODO: 2021/1/30 现在添加 JVM 到 root module 会导致 Gradle 依赖无法解决 - // https://github.com/mamoe/mirai/issues/932 - } - "metadata" -> { // TODO: 2021/1/21 seems no use. none `type` is "metadata" - publication.artifactId = "${project.name}-metadata" - } - "common" -> { - } - else -> { - // "jvm", "native", "js" - publication.artifactId = "${project.name}-$type" + for (publication in nonJvmPublications) { + configureMultiplatformPublication(publication, stubJavadoc, publication.name) + } + for (publication in jvmPublications) { +// publications.remove(publication) +// val newPublication = +// publications.register(publication.name + "Shadowed", MavenPublication::class.java) { +// val target = kotlinTargets.orEmpty().single { it.targetName == publication.name } +// from(target.components.single()) +// this.groupId = publication.groupId +// this.artifactId = publication.artifactId +// this.version = publication.version +// artifacts { +// publication.artifacts +// .filter { !(it.classifier.isNullOrEmpty() && it.extension == "jar") } // not .jar +// .forEach { artifact(it) } // copy Kotlin metadata artifacts +// } +// artifacts.removeAll { it.classifier.isNullOrEmpty() && it.extension == "jar" } +// // add relocated jar +// tasks.findByName("relocate${publication.name.titlecase()}Dependencies")?.let { relocation -> +// artifact(relocation) { +// classifier = "" +// extension = "jar" +// } +// } +// } + configureMultiplatformPublication(publication, stubJavadoc, publication.name) + publication.apply { + artifacts.filter { it.classifier.isNullOrEmpty() && it.extension == "jar" }.forEach { + it.builtBy(tasks.findByName("relocate${publication.name.titlecase()}Dependencies")) } } } @@ -75,6 +85,35 @@ fun Project.configureMppPublishing() { } } +private fun Project.configureMultiplatformPublication( + publication: MavenPublication, + stubJavadoc: TaskProvider, + moduleName: String, +) { + // Maven Central always require javadoc.jar + publication.artifact(stubJavadoc) + publication.setupPom(project) + + logPublishing(publication.name + ": moduleName = $moduleName") + when (moduleName) { + "kotlinMultiplatform" -> { + publication.artifactId = project.name + + // publishPlatformArtifactsInRootModule(publications.getByName("jvm") as MavenPublication) + + // TODO: 2021/1/30 现在添加 JVM 到 root module 会导致 Gradle 依赖无法解决 + // https://github.com/mamoe/mirai/issues/932 + } + "metadata" -> { // TODO: 2021/1/21 seems no use. none `type` is "metadata" + publication.artifactId = "${project.name}-metadata" + } + else -> { + // "jvm", "native", "js", "common" + publication.artifactId = "${project.name}-$moduleName" + } + } +} + val publishPlatformArtifactsInRootModule: Project.(MavenPublication) -> Unit = { platformPublication -> lateinit var platformPomBuilder: XmlProvider platformPublication.pom.withXml { platformPomBuilder = this } diff --git a/buildSrc/src/main/kotlin/ProjectConfigure.kt b/buildSrc/src/main/kotlin/ProjectConfigure.kt index 2049318dc..1d1908847 100644 --- a/buildSrc/src/main/kotlin/ProjectConfigure.kt +++ b/buildSrc/src/main/kotlin/ProjectConfigure.kt @@ -111,8 +111,8 @@ fun Project.configureKotlinTestSettings() { dependencies { "testImplementation"(kotlin("test-junit5"))?.because(b) - "testApi"("org.junit.jupiter:junit-jupiter-api:${Versions.junit}")?.because(b) - "testRuntimeOnly"("org.junit.jupiter:junit-jupiter-engine:${Versions.junit}")?.because(b) + "testApi"(`junit-jupiter-api`)?.because(b) + "testRuntimeOnly"(`junit-jupiter-engine`)?.because(b) } } isKotlinMpp -> { @@ -121,8 +121,8 @@ fun Project.configureKotlinTestSettings() { sourceSet.dependencies { implementation(kotlin("test-junit5"))?.because(b) - implementation("org.junit.jupiter:junit-jupiter-api:${Versions.junit}")?.because(b) - runtimeOnly("org.junit.jupiter:junit-jupiter-engine:${Versions.junit}")?.because(b) + implementation(`junit-jupiter-api`)?.because(b) + runtimeOnly(`junit-jupiter-engine`)?.because(b) } } diff --git a/buildSrc/src/main/kotlin/Shadow.kt b/buildSrc/src/main/kotlin/Shadow.kt new file mode 100644 index 000000000..e2ea3ebc2 --- /dev/null +++ b/buildSrc/src/main/kotlin/Shadow.kt @@ -0,0 +1,276 @@ +/* + * Copyright 2019-2022 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/dev/LICENSE + */ + +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import com.google.gson.Gson +import com.google.gson.GsonBuilder +import org.gradle.api.DomainObjectCollection +import org.gradle.api.Project +import org.gradle.api.publish.tasks.GenerateModuleMetadata +import org.gradle.kotlin.dsl.create +import org.gradle.kotlin.dsl.creating +import org.gradle.kotlin.dsl.extra +import org.gradle.kotlin.dsl.get +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType +import org.jetbrains.kotlin.gradle.plugin.KotlinTarget +import java.io.File + +fun Project.configureMppShadow() { + val kotlin = kotlinMpp ?: return + + configure(kotlin.targets.filter { + it.platformType == org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.jvm + && it.attributes.getAttribute(MIRAI_PLATFORM_ATTRIBUTE) == null + }) { + configureRelocationForTarget(project) + } + + // regular shadow file, with suffix `-all` + configureRegularShadowJar(kotlin) +} + +/** + * Relocate some dependencies for `.jar` + */ +private fun KotlinTarget.configureRelocationForTarget(project: Project) = project.run { + val relocateDependencies = + // e.g. relocateJvmDependencies + tasks.create("relocate${targetName.titlecase()}Dependencies", ShadowJar::class) { + group = "mirai" + description = "Relocate dependencies to internal package" + destinationDirectory.set(buildDir.resolve("libs")) +// archiveClassifier.set("") + archiveBaseName.set("${project.name}-${targetName.toLowerCase()}") + + dependsOn(compilations["main"].compileKotlinTask) // compileKotlinJvm + + // Run after all *Jar tasks from all projects, since Kotlin compiler may depend on the .jar file, concurrently modifying the jar will cause Kotlin compiler to fail. +// allprojects +// .asSequence() +// .flatMap { it.tasks } +// .filter { it.name.contains("compileKotlin") } +// .forEach { jar -> +// mustRunAfter(jar) +// } + + from(compilations["main"].output) + +// // change name to +// doLast { +// outputs.files.singleFile.renameTo( +// outputs.files.singleFile.parentFile.resolve( +// "${project.name}-${targetName.toLowerCase()}-${project.version}.jar" +// ) +// ) +// } + // Filter only those should be relocated + + afterEvaluate { + setRelocations() + + var fileFiltered = relocationFilters.isEmpty() + from(project.configurations.getByName("${targetName}RuntimeClasspath") + .files + .filter { file -> + relocationFilters.any { filter -> + // file.absolutePath example: /Users/xxx/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk8/1.7.0-RC/7f9f07fc65e534c15a820f61d846b9ffdba8f162/kotlin-stdlib-jdk8-1.7.0-RC.jar + filter.matchesFile(file) + }.also { + fileFiltered = fileFiltered || it + if (it) { + println("Including file: ${file.absolutePath}") + } + } + } + ) + check(fileFiltered) { "[Shadow Relocation] Expected at least one file filtered for target $targetName. Filters: $relocationFilters" } + } + } + + val allTasks = rootProject.allprojects.asSequence().flatMap { it.tasks } + allTasks + .filter { + it.name.startsWith("publish${targetName.titlecase()}PublicationTo") + } + .onEach { it.dependsOn(relocateDependencies) } + .count().let { + check(it > 0) { "[Shadow Relocation] Expected at least one publication matched for target $targetName." } + } + + // Ensure all compilation has finished, otherwise Kotlin compiler will complain. + allTasks + .filter { it.name.endsWith("Jar") } + .onEach { relocateDependencies.dependsOn(it) } + .count().let { + check(it > 0) { "[Shadow Relocation] Expected at least one task matched for target $targetName." } + } + + allTasks + .filter { it.name.startsWith("compileKotlin") } + .onEach { relocateDependencies.dependsOn(it) } + .count().let { + check(it > 0) { "[Shadow Relocation] Expected at least one task matched for target $targetName." } + } + + val metadataTask = + tasks.getByName("generateMetadataFileFor${targetName.capitalize()}Publication") as GenerateModuleMetadata + relocateDependencies.dependsOn(metadataTask) + + afterEvaluate { + // remove dependencies in Maven pom + mavenPublication { + pom.withXml { + val node = this.asNode().getSingleChild("dependencies") + val dependencies = node.childrenNodes() + logger.trace("[Shadow Relocation] deps: $dependencies") + dependencies.forEach { dep -> + val groupId = dep.getSingleChild("groupId").value().toString() + val artifactId = dep.getSingleChild("artifactId").value().toString() + logger.trace("[Shadow Relocation] Checking $groupId:$artifactId") + + if ( + relocationFilters.any { filter -> + filter.matchesDependency(groupId = groupId, artifactId = artifactId) + } + ) { + println("[Shadow Relocation] Filtering out $groupId:$artifactId from pom") + check(node.remove(dep)) { "Failed to remove dependency node" } + } + } + } + } + + // remove dependencies in Kotlin module metadata + relocateDependencies.doLast { + // mirai-core-jvm-2.13.0.module + val file = metadataTask.outputFile.asFile.get() + val metadata = Gson().fromJson( + file.readText(), + com.google.gson.JsonElement::class.java + ).asJsonObject + + val metadataVersion = metadata["formatVersion"]?.asString + check(metadataVersion == "1.1") { + "Unsupported Kotlin metadata version. version=$metadataVersion, file=${file.absolutePath}" + } + for (variant in metadata["variants"]!!.asJsonArray) { + val dependencies = variant.asJsonObject["dependencies"]!!.asJsonArray + dependencies.removeAll { dependency -> + val dep = dependency.asJsonObject + + val groupId = dep["group"]!!.asString + val artifactId = dep["module"]!!.asString + relocationFilters.any { filter -> + filter.matchesDependency( + groupId = groupId, + artifactId = artifactId + ) + }.also { + println("[Shadow Relocation] Filtering out $groupId:$artifactId from Kotlin module") + } + } + } + + + file.writeText(GsonBuilder().setPrettyPrinting().create().toJson(metadata)) + } + } +} + +private fun Project.configureRegularShadowJar(kotlin: KotlinMultiplatformExtension) { + if (project.configurations.findByName("jvmRuntimeClasspath") != null) { + val shadowJvmJar by tasks.creating(ShadowJar::class) sd@{ + group = "mirai" + archiveClassifier.set("-all") + + val compilations = + kotlin.targets.filter { it.platformType == KotlinPlatformType.jvm } + .map { it.compilations["main"] } + + compilations.forEach { + dependsOn(it.compileKotlinTask) + from(it.output) + } + + setRelocations() + + from(project.configurations.findByName("jvmRuntimeClasspath")) + + this.exclude { file -> + file.name.endsWith(".sf", ignoreCase = true) + } + + /* + this.manifest { + this.attributes( + "Manifest-Version" to 1, + "Implementation-Vendor" to "Mamoe Technologies", + "Implementation-Title" to this.name.toString(), + "Implementation-Version" to this.version.toString() + ) + }*/ + } + } +} + +data class RelocationFilter( + val groupId: String, + val artifactId: String? = null, + val shadowFilter: String = groupId, + val filesFilter: String = groupId.replace(".", "/") +) { + + fun matchesFile(file: File): Boolean { + val path = file.absolutePath.replace("\\", "/") + return filesFilter in path + || groupId in path + } + + fun matchesDependency(groupId: String?, artifactId: String?): Boolean { + if (this.groupId == groupId) return true + if (this.artifactId != null && this.artifactId == artifactId) return true + + return false + } +} + +val Project.relocationFilters: DomainObjectCollection + get() { + if (project.extra.has("relocationFilters")) { + @Suppress("UNCHECKED_CAST") + return project.extra.get("relocationFilters") as DomainObjectCollection + + } else { + val container = project.objects.domainObjectSet(RelocationFilter::class.java) + project.extra.set("relocationFilters", container) + return container + } + } + +private const val relocationRootPackage = "net.mamoe.mirai.internal.deps" + +private fun ShadowJar.setRelocations() { + project.relocationFilters.forEach { relocation -> + relocate(relocation.shadowFilter, "$relocationRootPackage.${relocation.groupId}") + } +} + +fun Project.configureRelocationForCore() { + relocateAllFromGroupId("io.ktor") +} + +fun Project.relocateAllFromGroupId(groupId: String) { + relocationFilters.add(RelocationFilter(groupId)) +} + +// This does not include transitive dependencies +fun Project.relocateExactArtifact(groupId: String, artifactId: String) { + relocationFilters.add(RelocationFilter(groupId, artifactId)) +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 874455250..ddff57985 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -13,6 +13,9 @@ import org.gradle.api.attributes.Attribute import org.gradle.kotlin.dsl.exclude import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler +// DO NOT CHANGE FILENAME OR RELATIVE PATH TO ROOT PROJECT. +// mirai-deps-test DEPENDS ON THE PATH. + object Versions { val project = System.getenv("mirai.build.project.version") ?: /*PROJECT_VERSION_START*/"2.13.0"/*PROJECT_VERSION_END*/ @@ -22,11 +25,11 @@ object Versions { val consoleIntellij = "221-$project-162-1" // idea-mirai-kotlin-patch val consoleTerminal = project - const val kotlinCompiler = "1.7.0-RC" + const val kotlinCompiler = "1.7.0" const val kotlinStdlib = kotlinCompiler const val dokka = "1.6.21" - const val kotlinCompilerForIdeaPlugin = "1.7.0-RC" + const val kotlinCompilerForIdeaPlugin = "1.7.0" const val coroutines = "1.6.2" const val atomicFU = "0.17.2" @@ -40,6 +43,7 @@ object Versions { const val blockingBridge = "2.1.0-170.1" const val dynamicDelegation = "0.3.0-170.1" + const val mavenCentralPublish = "1.0.0-dev-3" const val androidGradlePlugin = "4.1.1" const val android = "4.1.1.4" @@ -138,7 +142,9 @@ const val `kotlin-stdlib-jdk8` = "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${Vers const val `kotlin-reflect` = "org.jetbrains.kotlin:kotlin-reflect:${Versions.kotlinStdlib}" const val `kotlin-test` = "org.jetbrains.kotlin:kotlin-test:${Versions.kotlinStdlib}" const val `kotlin-test-junit5` = "org.jetbrains.kotlin:kotlin-test-junit5:${Versions.kotlinStdlib}" - +const val `junit-jupiter-api` = "org.junit.jupiter:junit-jupiter-api:${Versions.junit}" +const val `junit-jupiter-params` = "org.junit.jupiter:junit-jupiter-params:${Versions.junit}" +const val `junit-jupiter-engine` = "org.junit.jupiter:junit-jupiter-engine:${Versions.junit}" //const val `mirai-core-api` = "net.mamoe:mirai-core-api:${Versions.core}" //const val `mirai-core` = "net.mamoe:mirai-core:${Versions.core}" diff --git a/buildSrc/src/main/kotlin/utils.kt b/buildSrc/src/main/kotlin/utils.kt index 8c6d731d3..9b341356e 100644 --- a/buildSrc/src/main/kotlin/utils.kt +++ b/buildSrc/src/main/kotlin/utils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019-2021 Mamoe Technologies and contributors. + * Copyright 2019-2022 Mamoe Technologies and contributors. * * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. @@ -7,6 +7,8 @@ * https://github.com/mamoe/mirai/blob/dev/LICENSE */ +import groovy.util.Node +import groovy.util.NodeList import java.io.InputStream import java.io.OutputStream import java.security.MessageDigest @@ -60,3 +62,14 @@ fun InputStream.md5(): ByteArray { } return digest.digest() } + + + + +fun Node.getSingleChild(name: String): Node { + return (this.get(name) as NodeList).single() as Node +} + +fun Node.childrenNodes(): List { + return this.children().filterIsInstance() +} \ No newline at end of file diff --git a/mirai-console/tools/gradle-plugin/build.gradle.kts b/mirai-console/tools/gradle-plugin/build.gradle.kts index 65445c400..89af28b53 100644 --- a/mirai-console/tools/gradle-plugin/build.gradle.kts +++ b/mirai-console/tools/gradle-plugin/build.gradle.kts @@ -46,14 +46,13 @@ dependencies { implementation(`log4j-core`) testApi(kotlin("test-junit5")) - testApi("org.junit.jupiter:junit-jupiter-api:${Versions.junit}") - testApi("org.junit.jupiter:junit-jupiter-params:${Versions.junit}") + testApi(`junit-jupiter-api`) + testApi(`junit-jupiter-params`) "integTestApi"(kotlin("test-junit5")) - "integTestApi"("org.junit.jupiter:junit-jupiter-api:${Versions.junit}") - "integTestApi"("org.junit.jupiter:junit-jupiter-params:${Versions.junit}") - "integTestImplementation"("org.junit.jupiter:junit-jupiter-engine:${Versions.junit}") -// "integTestImplementation"("org.spockframework:spock-core:1.3-groovy-2.5") + "integTestApi"(`junit-jupiter-api`) + "integTestApi"(`junit-jupiter-params`) + "integTestImplementation"(`junit-jupiter-engine`) "integTestImplementation"(gradleTestKit()) kotlinVersionForIntegrationTest(kotlin("gradle-plugin", "1.5.21")) diff --git a/mirai-core-all/build.gradle.kts b/mirai-core-all/build.gradle.kts index 35ae7470d..28f5e1c52 100644 --- a/mirai-core-all/build.gradle.kts +++ b/mirai-core-all/build.gradle.kts @@ -1,10 +1,10 @@ /* - * Copyright 2019-2021 Mamoe Technologies and contributors. + * Copyright 2019-2022 Mamoe Technologies and contributors. * - * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. - * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. * - * https://github.com/mamoe/mirai/blob/master/LICENSE + * https://github.com/mamoe/mirai/blob/dev/LICENSE */ @file:Suppress("UnusedImport") @@ -27,4 +27,6 @@ dependencies { if (System.getenv("MIRAI_IS_SNAPSHOTS_PUBLISHING")?.toBoolean() != true) { configurePublishing("mirai-core-all") -} \ No newline at end of file +} + +configureRelocationForCore() \ No newline at end of file diff --git a/mirai-core-api/build.gradle.kts b/mirai-core-api/build.gradle.kts index f39c75d7e..93c57311f 100644 --- a/mirai-core-api/build.gradle.kts +++ b/mirai-core-api/build.gradle.kts @@ -18,6 +18,7 @@ plugins { id("signing") id("me.him188.kotlin-jvm-blocking-bridge") id("me.him188.kotlin-dynamic-delegation") +// id("me.him188.maven-central-publish") `maven-publish` } @@ -105,4 +106,13 @@ if (tasks.findByName("androidMainClasses") != null) { } configureMppPublishing() -configureBinaryValidators(setOf("jvm", "android").filterTargets()) \ No newline at end of file +configureBinaryValidators(setOf("jvm", "android").filterTargets()) +configureRelocationForCore() + +//mavenCentralPublish { +// artifactId = "mirai-core-api" +// githubProject("mamoe", "mirai") +// developer("Mamoe Technologies", email = "support@mamoe.net", url = "https://github.com/mamoe") +// licenseFromGitHubProject("AGPLv3", "dev") +// publishPlatformArtifactsInRootModule = "jvm" +//} \ No newline at end of file diff --git a/mirai-core-utils/build.gradle.kts b/mirai-core-utils/build.gradle.kts index 494c1505d..a6b4b8cdb 100644 --- a/mirai-core-utils/build.gradle.kts +++ b/mirai-core-utils/build.gradle.kts @@ -15,6 +15,7 @@ plugins { id("kotlinx-atomicfu") id("me.him188.kotlin-jvm-blocking-bridge") +// id("me.him188.maven-central-publish") `maven-publish` } @@ -94,22 +95,13 @@ if (tasks.findByName("androidMainClasses") != null) { tasks.getByName("androidTest").dependsOn("checkAndroidApiLevel") } -fun org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler.implementation1(dependencyNotation: String) = - implementation(dependencyNotation) { - exclude("org.jetbrains.kotlin", "kotlin-stdlib") - exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core") - exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core-common") - exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core-jvm") - exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core-metadata") - } - -fun org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler.api1(dependencyNotation: String) = - api(dependencyNotation) { - exclude("org.jetbrains.kotlin", "kotlin-stdlib") - exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core") - exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core-common") - exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core-jvm") - exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core-metadata") - } - configureMppPublishing() +configureRelocationForCore() + +//mavenCentralPublish { +// artifactId = "mirai-core-utils" +// githubProject("mamoe", "mirai") +// developer("Mamoe Technologies", email = "support@mamoe.net", url = "https://github.com/mamoe") +// licenseFromGitHubProject("AGPLv3", "dev") +// publishPlatformArtifactsInRootModule = "jvm" +//} \ No newline at end of file diff --git a/mirai-core/build.gradle.kts b/mirai-core/build.gradle.kts index 12a52d614..da87f5b12 100644 --- a/mirai-core/build.gradle.kts +++ b/mirai-core/build.gradle.kts @@ -19,6 +19,7 @@ plugins { kotlin("plugin.serialization") id("me.him188.kotlin-jvm-blocking-bridge") id("me.him188.kotlin-dynamic-delegation") +// id("me.him188.maven-central-publish") `maven-publish` } @@ -202,4 +203,13 @@ if (tasks.findByName("androidMainClasses") != null) { } configureMppPublishing() -configureBinaryValidators(setOf("jvm", "android").filterTargets()) \ No newline at end of file +configureBinaryValidators(setOf("jvm", "android").filterTargets()) +configureRelocationForCore() + +//mavenCentralPublish { +// artifactId = "mirai-core" +// githubProject("mamoe", "mirai") +// developer("Mamoe Technologies", email = "support@mamoe.net", url = "https://github.com/mamoe") +// licenseFromGitHubProject("AGPLv3", "dev") +// publishPlatformArtifactsInRootModule = "jvm" +//} \ No newline at end of file diff --git a/mirai-deps-test/.gitignore b/mirai-deps-test/.gitignore new file mode 100644 index 000000000..dfb020d7c --- /dev/null +++ b/mirai-deps-test/.gitignore @@ -0,0 +1 @@ +src/BuildConfig.kt \ No newline at end of file diff --git a/mirai-deps-test/README.md b/mirai-deps-test/README.md new file mode 100644 index 000000000..4e75b3941 --- /dev/null +++ b/mirai-deps-test/README.md @@ -0,0 +1,3 @@ +# native-deps-test + +测试 Native \ No newline at end of file diff --git a/mirai-deps-test/build.gradle.kts b/mirai-deps-test/build.gradle.kts new file mode 100644 index 000000000..4c5ff23e1 --- /dev/null +++ b/mirai-deps-test/build.gradle.kts @@ -0,0 +1,100 @@ +/* + * Copyright 2019-2022 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/dev/LICENSE + */ + +@file:Suppress("UnusedImport") + +plugins { + kotlin("jvm") + id("java-gradle-plugin") +} + +dependencies { + implementation(gradleApi()) + implementation(gradleKotlinDsl()) + implementation(kotlin("gradle-plugin-api")) + implementation(kotlin("gradle-plugin")) + implementation(kotlin("stdlib")) + + api("com.github.jengelman.gradle.plugins:shadow:6.0.0") + api(`jetbrains-annotations`) + + testImplementation(kotlin("test-junit5")) + testImplementation(`junit-jupiter-api`) + testImplementation(`junit-jupiter-params`) + testRuntimeOnly(`junit-jupiter-engine`) +} + +tasks.getByName("test", Test::class) { + environment("mirai.root.project.dir", rootProject.projectDir.absolutePath) +} + +val publishMiraiArtifactsToMavenLocal by tasks.registering { + group = "mirai" + description = "Publish all mirai artifacts to MavenLocal" + val publishTasks = rootProject.allprojects.mapNotNull { proj -> + proj.tasks.findByName("publishToMavenLocal") + } + dependsOn(publishTasks) + + doLast { + // delete shadowed Jars, since Kotlin can't compile modules that depend on them. + rootProject.subprojects + .asSequence() + .flatMap { proj -> proj.tasks.filter { task -> task.name.contains("relocate") } } + .flatMap { it.outputs.files } + .filter { it.isFile && it.name.endsWith(".jar") } + .forEach { it.delete() } + } +} + +tasks.register("generateBuildConfig") { + group = "mirai" + + doLast { + val text = """ + package net.mamoe.mirai.deps.test + + /** + * This file was generated by Gradle task `generateBuildConfig`. + */ + object BuildConfig { + /** + * Kotlin version used to compile mirai-core + */ + const val kotlinVersion = "${Versions.kotlinCompiler}" + } + """.trimIndent() + "\n" + val file = project.projectDir.resolve("src/BuildConfig.kt") + if (!file.exists() || file.readText() != text) { + file.writeText(text) + } + } + tasks.getByName("assemble").dependsOn(this) // if src is empty, compileKotlin will be skipped. + tasks.getByName("compileKotlin").dependsOn(this) + tasks.getByName("compileTestKotlin").dependsOn(this) +} + +tasks.register("publishMiraiLocalArtifacts", Exec::class) { + group = "mirai" + description = "Starts a child process to publish v2.99.0-deps-test artifacts to MavenLocal" + + workingDir(rootProject.projectDir) + environment("mirai.build.project.version", "2.99.0-deps-test") + commandLine( + "./gradlew", + publishMiraiArtifactsToMavenLocal.name, + "--no-daemon", + "-Pkotlin.compiler.execution.strategy=in-process" + ) + standardOutput = System.out + errorOutput = System.err +} + + +version = Versions.core diff --git a/mirai-deps-test/gradle.properties b/mirai-deps-test/gradle.properties new file mode 100644 index 000000000..a6d6075ef --- /dev/null +++ b/mirai-deps-test/gradle.properties @@ -0,0 +1,9 @@ +# +# Copyright 2019-2022 Mamoe Technologies and contributors. +# +# 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. +# Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. +# +# https://github.com/mamoe/mirai/blob/dev/LICENSE +# + diff --git a/mirai-deps-test/test/AbstractTest.kt b/mirai-deps-test/test/AbstractTest.kt new file mode 100644 index 000000000..ccacd0af5 --- /dev/null +++ b/mirai-deps-test/test/AbstractTest.kt @@ -0,0 +1,173 @@ +/* + * Copyright 2019-2022 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/dev/LICENSE + */ + +package net.mamoe.mirai.deps.test + +import org.gradle.api.internal.artifacts.mvnsettings.DefaultMavenFileLocations +import org.gradle.testkit.runner.GradleRunner +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.extension.AfterEachCallback +import org.junit.jupiter.api.extension.RegisterExtension +import org.junit.jupiter.api.io.TempDir +import java.io.File + +// Copied from mirai-console-gradle +abstract class AbstractTest { + companion object { + const val miraiLocalVersion = "2.99.0-deps-test" // do Search Everywhere before changing this + const val REASON_LOCAL_ARTIFACT_NOT_AVAILABLE = "local artifacts not available" + + private val mavenLocalDir: File by lazy { + org.gradle.api.internal.artifacts.mvnsettings.DefaultLocalMavenRepositoryLocator( + org.gradle.api.internal.artifacts.mvnsettings.DefaultMavenSettingsProvider(DefaultMavenFileLocations()) + ).localMavenRepository + } + + @JvmStatic + fun isMiraiLocalAvailable(): Boolean { + return if (mavenLocalDir.resolve("net/mamoe/mirai-core/$miraiLocalVersion").exists()) { + println( + """ + [mirai-deps-test] Found local artifacts `$miraiLocalVersion`! + Please note that you may need to manually update local artifacts if you have: + - added/removed a dependency for mirai-core series modules + - changed version of any of the dependencies for mirai-core series modules + + You can update by running `./gradlew publishMiraiLocalArtifacts`. + """.trimIndent() + ) + true + } else { + System.err.println( + """ + [mirai-deps-test] ERROR: Test is not run, because there are no local artifacts available for dependencies testing. + Please build and publish local artifacts with version `$miraiLocalVersion` before running this test(:mirai-deps-test:test). + This could have be automated but it will take a huge amount of time for your routine testing. + + You can run this test manually if you have: + - added/removed a dependency for mirai-core series modules + - changed version of any of the dependencies for mirai-core series modules + + Note that you can ignore this test if you did not change project (dependency) structure. + And you don't need to worry if you does not run this test — this test is always executed on the CI when you make a PR. + + You can run `./gradlew publishMiraiLocalArtifacts` to publish local artifacts. + Then you can run this test again. (By your original way or ./gradlew :mirai-deps-test:test) + """.trimIndent() + ) + false + } + } + } + + @JvmField + @TempDir + var tempDirField: File? = null + + val tempDir: File get() = tempDirField!! + + val kotlinVersion = BuildConfig.kotlinVersion + + lateinit var mainSrcDir: File + lateinit var commonMainSrcDir: File + lateinit var nativeMainSrcDir: File + lateinit var testDir: File + lateinit var buildFile: File + lateinit var settingsFile: File + lateinit var propertiesFile: File + + + @OptIn(ExperimentalStdlibApi::class) + fun runGradle(vararg arguments: String) { + System.gc() + GradleRunner.create() + .withProjectDir(tempDir) + .withPluginClasspath() + .withGradleVersion("7.2") + .forwardOutput() + .withEnvironment(System.getenv()) + .withArguments(buildList { + addAll(arguments) + add("-Pkotlin.compiler.execution.strategy=in-process") + add("-Dorg.gradle.jvmargs=-Xmx512m -Dfile.encoding=UTF-8") + add("--stacktrace") + }) + .build() + } + + @BeforeEach + fun setup() { + println("Temp path is " + tempDir.absolutePath) + + settingsFile = File(tempDir, "settings.gradle") + settingsFile.delete() + settingsFile.writeText( + """ + pluginManagement { + repositories { + gradlePluginPortal() + mavenCentral() + mavenLocal() + } + } + """ + ) + + File(tempDir, "gradle.properties").apply { + delete() + writeText( + """ + org.gradle.daemon=false + org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8 + """.trimIndent() + ) + } + mainSrcDir = tempDir.resolve("src/main/kotlin").apply { mkdirs() } + commonMainSrcDir = tempDir.resolve("src/commonMain/kotlin").apply { mkdirs() } + nativeMainSrcDir = tempDir.resolve("src/nativeMain/kotlin").apply { mkdirs() } + testDir = tempDir.resolve("src/test/kotlin").apply { mkdirs() } + + buildFile = tempDir.resolve("build.gradle.kts") + buildFile.writeText( + """ + import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + plugins { + kotlin("jvm") version "1.7.0" + } + group = "org.example" + version = "1.0-SNAPSHOT" + repositories { + mavenCentral() + mavenLocal() + } + dependencies { + testImplementation(kotlin("test")) + } + tasks.test { + useJUnitPlatform() + } + tasks.withType { + kotlinOptions.jvmTarget = "1.8" + } + """.trimIndent() + "\n\n" + ) + } + + @JvmField + @RegisterExtension + internal val after: AfterEachCallback = AfterEachCallback { context -> + if (context.executionException.isPresent) { + val inst = context.requiredTestInstance as AbstractTest + println("====================== build.gradle ===========================") + println(inst.tempDir.resolve("build.gradle").readText()) + println("==================== settings.gradle ==========================") + println(inst.tempDir.resolve("settings.gradle").readText()) + } + } +} \ No newline at end of file diff --git a/mirai-deps-test/test/CoreDependencyResolutionTest.kt b/mirai-deps-test/test/CoreDependencyResolutionTest.kt new file mode 100644 index 000000000..54be16c2f --- /dev/null +++ b/mirai-deps-test/test/CoreDependencyResolutionTest.kt @@ -0,0 +1,167 @@ +/* + * Copyright 2019-2022 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/dev/LICENSE + */ + +package net.mamoe.mirai.deps.test + +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.condition.EnabledIf + +class CoreDependencyResolutionTest : AbstractTest() { + @Test + @EnabledIf("isMiraiLocalAvailable", disabledReason = REASON_LOCAL_ARTIFACT_NOT_AVAILABLE) + fun `test resolve JVM root from Kotlin JVM`() { + mainSrcDir.resolve("main.kt").writeText( + """ + package test + fun main () { + println(net.mamoe.mirai.BotFactory) + } + """.trimIndent() + ) + buildFile.writeText( + """ + plugins { + id("org.jetbrains.kotlin.jvm") version "$kotlinVersion" + } + repositories { + mavenCentral() + mavenLocal() + } + dependencies { + implementation("net.mamoe:mirai-core:$miraiLocalVersion") + } + """.trimIndent() + ) + runGradle("build") + } + + @Test + @EnabledIf("isMiraiLocalAvailable", disabledReason = REASON_LOCAL_ARTIFACT_NOT_AVAILABLE) + fun `test resolve JVM from Kotlin JVM`() { + mainSrcDir.resolve("main.kt").writeText( + """ + package test + fun main () { + println(net.mamoe.mirai.BotFactory) + } + """.trimIndent() + ) + buildFile.writeText( + """ + plugins { + id("org.jetbrains.kotlin.jvm") version "$kotlinVersion" + } + repositories { + mavenCentral() + mavenLocal() + } + dependencies { + implementation("net.mamoe:mirai-core-jvm:$miraiLocalVersion") + } + """.trimIndent() + ) + runGradle("build") + } + + @Test + @EnabledIf("isMiraiLocalAvailable", disabledReason = REASON_LOCAL_ARTIFACT_NOT_AVAILABLE) + fun `test resolve JVM and Native from common`() { + commonMainSrcDir.resolve("main.kt").writeText( + """ + package test + fun main () { + println(net.mamoe.mirai.BotFactory) + } + """.trimIndent() + ) + buildFile.writeText( + """ + |import org.apache.tools.ant.taskdefs.condition.Os + |import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet + | + |plugins { + | id("org.jetbrains.kotlin.multiplatform") version "$kotlinVersion" + |} + |repositories { + | mavenCentral() + | mavenLocal() + |} + |kotlin { + | targets { + | jvm() + | val nativeMainSets = mutableListOf() + | val nativeTestSets = mutableListOf() + | when { + | Os.isFamily(Os.FAMILY_MAC) -> if (Os.isArch("aarch64")) macosArm64("native") else macosX64("native") + | Os.isFamily(Os.FAMILY_WINDOWS) -> mingwX64("native") + | else -> linuxX64("native") + | } + | } + | sourceSets { + | val commonMain by getting { + | dependencies { + | api("net.mamoe:mirai-core:$miraiLocalVersion") + | } + | } + | } + |} + """.trimMargin() + ) + + runGradle("build") + } + + @Test + @EnabledIf("isMiraiLocalAvailable", disabledReason = REASON_LOCAL_ARTIFACT_NOT_AVAILABLE) + fun `test resolve Native from common`() { + nativeMainSrcDir.resolve("main.kt").writeText( + """ + package test + fun main () { + println(net.mamoe.mirai.BotFactory) + } + """.trimIndent() + ) + buildFile.writeText( + """ + |import org.apache.tools.ant.taskdefs.condition.Os + |import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet + | + |plugins { + | id("org.jetbrains.kotlin.multiplatform") version "$kotlinVersion" + |} + |repositories { + | mavenCentral() + | mavenLocal() + |} + |kotlin { + | targets { + | jvm() + | val nativeMainSets = mutableListOf() + | val nativeTestSets = mutableListOf() + | when { + | Os.isFamily(Os.FAMILY_MAC) -> if (Os.isArch("aarch64")) macosArm64("native") else macosX64("native") + | Os.isFamily(Os.FAMILY_WINDOWS) -> mingwX64("native") + | else -> linuxX64("native") + | } + | } + | sourceSets { + | val nativeMain by getting { + | dependencies { + | api("net.mamoe:mirai-core:$miraiLocalVersion") + | } + | } + | } + |} + """.trimMargin() + ) + + runGradle("build") + } +} \ No newline at end of file diff --git a/mirai-deps-test/test/CoreShadowRelocationTest.kt b/mirai-deps-test/test/CoreShadowRelocationTest.kt new file mode 100644 index 000000000..7b0fd94e8 --- /dev/null +++ b/mirai-deps-test/test/CoreShadowRelocationTest.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2019-2022 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/dev/LICENSE + */ + +package net.mamoe.mirai.deps.test + +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.condition.EnabledIf + +class CoreShadowRelocationTest : AbstractTest() { + @Test + @EnabledIf("isMiraiLocalAvailable", disabledReason = REASON_LOCAL_ARTIFACT_NOT_AVAILABLE) + fun `test OkHttp filtered out`() { + testDir.resolve("test.kt").writeText( + """ + package test + import org.junit.jupiter.api.* + class MyTest { + @Test + fun `test base dependency`() { + assertThrows { + Class.forName("io.ktor.client.engine.okhttp.OkHttp") + } + } + @Test + fun `test transitive dependency`() { + assertThrows { + Class.forName("okhttp3.OkHttpClient") + } + } + } + """.trimIndent() + ) + buildFile.appendText( + """ + dependencies { + implementation("net.mamoe:mirai-core:$miraiLocalVersion") + } + """.trimIndent() + ) + runGradle("check") + } +} \ No newline at end of file diff --git a/mirai-deps-test/test/package.kt b/mirai-deps-test/test/package.kt new file mode 100644 index 000000000..d00d8a359 --- /dev/null +++ b/mirai-deps-test/test/package.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2019-2022 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/dev/LICENSE + */ + +package net.mamoe.mirai.deps.test \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 7bfedc18b..04c7e2bbd 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,15 +1,15 @@ /* - * Copyright 2019-2021 Mamoe Technologies and contributors. + * Copyright 2019-2022 Mamoe Technologies and contributors. * - * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. - * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. * - * https://github.com/mamoe/mirai/blob/master/LICENSE + * https://github.com/mamoe/mirai/blob/dev/LICENSE */ pluginManagement { repositories { - if (System.getProperty("use.maven.local") == "true") { + if (System.getProperty("use.maven.local") == "true") { // you can enable by adding `systemProp.use.maven.local=true` in 'gradle.properties'. mavenLocal() } gradlePluginPortal() @@ -18,24 +18,31 @@ pluginManagement { } } -val allProjects = mutableListOf() rootProject.name = "mirai" +/** + * Projects included so far + */ +val allProjects = mutableListOf() + fun includeProject(projectPath: String, dir: String? = null) { include(projectPath) if (dir != null) project(projectPath).projectDir = file(dir) allProjects.add(project(projectPath)) } +fun includeConsoleProject(projectPath: String, dir: String? = null) = + includeProject(projectPath, "mirai-console/$dir") + + includeProject(":mirai-core-utils") includeProject(":mirai-core-api") includeProject(":mirai-core") + includeProject(":mirai-core-all") includeProject(":mirai-bom") includeProject(":mirai-dokka") - -//includeProject(":binary-compatibility-validator") -//includeProject(":binary-compatibility-validator-android", "binary-compatibility-validator/android") +includeProject(":mirai-deps-test") includeProject(":mirai-logging-log4j2", "logging/mirai-logging-log4j2") includeProject(":mirai-logging-slf4j", "logging/mirai-logging-slf4j") @@ -43,55 +50,50 @@ includeProject(":mirai-logging-slf4j-simple", "logging/mirai-logging-slf4j-simpl includeProject(":mirai-logging-slf4j-logback", "logging/mirai-logging-slf4j-logback") -val disableOldFrontEnds = true - -fun includeConsoleProject(projectPath: String, dir: String? = null) = - includeProject(projectPath, "mirai-console/$dir") - includeConsoleProject(":mirai-console-compiler-annotations", "tools/compiler-annotations") includeConsoleProject(":mirai-console", "backend/mirai-console") includeConsoleProject(":mirai-console.codegen", "backend/codegen") includeConsoleProject(":mirai-console-terminal", "frontend/mirai-console-terminal") -// region mirai-console.integration-test -includeConsoleProject(":mirai-console.integration-test", "backend/integration-test") - -val consoleIntegrationTestSubPluginBuildGradleKtsTemplate by lazy { - rootProject.projectDir - .resolve("mirai-console/backend/integration-test/testers") - .resolve("tester.template.gradle.kts") - .readText() -} - -@Suppress("SimpleRedundantLet") -fun includeConsoleITPlugin(prefix: String, path: File) { - path.resolve("build.gradle.kts").takeIf { !it.isFile }?.let { initScript -> - initScript.writeText(consoleIntegrationTestSubPluginBuildGradleKtsTemplate) - } - - val projectPath = "$prefix${path.name}" - include(projectPath) - project(projectPath).projectDir = path - path.listFiles()?.asSequence().orEmpty() - .filter { it.isDirectory } - .filter { it.resolve(".nested-module.txt").exists() } - .forEach { includeConsoleITPlugin("${projectPath}:", it) } -} -rootProject.projectDir - .resolve("mirai-console/backend/integration-test/testers") - .listFiles()?.asSequence().orEmpty() - .filter { it.isDirectory } - .forEach { includeConsoleITPlugin(":mirai-console.integration-test:", it) } -// endregion +includeConsoleIntegrationTestProjects() includeConsoleProject(":mirai-console-compiler-common", "tools/compiler-common") includeConsoleProject(":mirai-console-intellij", "tools/intellij-plugin") includeConsoleProject(":mirai-console-gradle", "tools/gradle-plugin") -@Suppress("ConstantConditionIf") -if (!disableOldFrontEnds) { - includeConsoleProject(":mirai-console-terminal", "frontend/mirai-console-terminal") +//includeConsoleFrontendGraphical() +includeProject(":ci-release-helper") + +includeBinaryCompatibilityValidatorProjects() + +/** + * Configures a project `:validator:path-to-project:target-name` for binary compatibility validation. + * + * To enable validation for a project, + * create a subdirectory with name of the target under "compatibility-validation", + * then sync **twice**. See `:mirai-core-api` for an example. + * + * **Note**: This function depends on [allProjects], and should be used at the end. + */ +fun includeBinaryCompatibilityValidatorProjects() { + val result = mutableListOf() + for (project in allProjects) { + val validationDir = project.projectDir.resolve("compatibility-validation") + if (!validationDir.exists()) continue + validationDir.listFiles().orEmpty().forEach { dir -> + if (dir.resolve("build.gradle.kts").isFile) { + val path = ":validator" + project.path + ":${dir.name}" + include(path) + project(path).projectDir = dir +// project(path).name = "${project.name}-validator-${dir.name}" + result.add(project(path)) + } + } + } +} + +fun includeConsoleLegacyFrontendProjects() { println("JDK version: ${JavaVersion.current()}") if (JavaVersion.current() >= JavaVersion.VERSION_1_9) { @@ -101,20 +103,34 @@ if (!disableOldFrontEnds) { } } -includeProject(":ci-release-helper") +fun includeConsoleIntegrationTestProjects() { + includeConsoleProject(":mirai-console.integration-test", "backend/integration-test") - -val result = mutableListOf() -for (project in allProjects) { - val validationDir = project.projectDir.resolve("compatibility-validation") - if (!validationDir.exists()) continue - validationDir.listFiles().orEmpty().forEach { dir -> - if (dir.resolve("build.gradle.kts").isFile) { - val path = ":validator" + project.path + ":${dir.name}" - include(path) - project(path).projectDir = dir -// project(path).name = "${project.name}-validator-${dir.name}" - result.add(project(path)) - } + val consoleIntegrationTestSubPluginBuildGradleKtsTemplate by lazy { + rootProject.projectDir + .resolve("mirai-console/backend/integration-test/testers") + .resolve("tester.template.gradle.kts") + .readText() } -} + + @Suppress("SimpleRedundantLet") + fun includeConsoleITPlugin(prefix: String, path: File) { + path.resolve("build.gradle.kts").takeIf { !it.isFile }?.let { initScript -> + initScript.writeText(consoleIntegrationTestSubPluginBuildGradleKtsTemplate) + } + + val projectPath = "$prefix${path.name}" + include(projectPath) + project(projectPath).projectDir = path + path.listFiles()?.asSequence().orEmpty() + .filter { it.isDirectory } + .filter { it.resolve(".nested-module.txt").exists() } + .forEach { includeConsoleITPlugin("${projectPath}:", it) } + } + + rootProject.projectDir + .resolve("mirai-console/backend/integration-test/testers") + .listFiles()?.asSequence().orEmpty() + .filter { it.isDirectory } + .forEach { includeConsoleITPlugin(":mirai-console.integration-test:", it) } +} \ No newline at end of file