From 17f8629ac4ca291c2831b59bd28bd29b685a7962 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Thu, 5 Nov 2026 10:10:16 +0100 Subject: [PATCH 1/2] build: Assemble dist zips from a local Maven repo layout Craft expects Maven file names in each dist dir, e.g. --javadoc.jar. We used to copy build outputs and rename them to match, so the rules broke whenever a plugin changed its output names. The vanniktech maven-publish 0.30.0 -> 0.37.0 bump (#6412) added the version to the KMP javadoc jars, so sentry-compose--javadoc.jar was missing and the 8.63.0 publish failed. Now every module also publishes to build/distMaven and the dist zips copy from its Maven layout, where file names are fixed by Maven itself. Only the craft-specific names are renamed (pom-default.xml, -release.aar). The zip contents are unchanged. Co-Authored-By: Claude Opus 5.5 --- build.gradle.kts | 6 ++ buildSrc/src/main/java/Publication.kt | 124 +++++++------------------- 2 files changed, 40 insertions(+), 90 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index a2f7bb27df8..7f4f96295b7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -99,6 +99,7 @@ subprojects { tasks.named("distZip").configure { this.dependsOn("publishToMavenLocal") + this.dependsOn("publishAllPublicationsTo${DIST_MAVEN_REPO.replaceFirstChar { it.uppercase() }}Repository") val file = this.project.layout.buildDirectory.file("distributions${sep}${this.project.name}-${this.project.version}.zip").get().asFile this.doLast { if (!file.exists()) throw IllegalStateException("Distribution file: ${file.absolutePath} does not exist") @@ -129,6 +130,11 @@ subprojects { // this is needed for sentry-unity to consume our artifacts locally as proper maven publication configure { repositories { + // the dist zips craft publishes are assembled from this, see Publication.kt + maven { + name = DIST_MAVEN_REPO + url = distMavenDir().get().asFile.toURI() + } maven { name = "unityMaven" url = rootProject.layout.buildDirectory.file("unityMaven").get().asFile.toURI() diff --git a/buildSrc/src/main/java/Publication.kt b/buildSrc/src/main/java/Publication.kt index d545e6e32dc..aa73da0aec6 100644 --- a/buildSrc/src/main/java/Publication.kt +++ b/buildSrc/src/main/java/Publication.kt @@ -1,110 +1,54 @@ import org.gradle.api.Project import org.gradle.api.distribution.DistributionContainer import org.gradle.api.file.CopySpec -import java.io.File -private object Consts { - val taskRegex = Regex("(.*)DistZip") -} +/** + * Name of the per-project Maven repository the dist zips are assembled from. + * `distZip` depends on `publishAllPublicationsToDistMavenRepository`. + */ +const val DIST_MAVEN_REPO = "distMaven" + +fun Project.distMavenDir() = layout.buildDirectory.dir(DIST_MAVEN_REPO) private fun Project.versionName(): String = providers.gradleProperty("versionName").get() // configure distZip tasks for multiplatform fun DistributionContainer.configureForMultiplatform(project: Project) { - val sep = File.separator - val version = project.versionName() - val name = project.name - - this.maybeCreate("android").contents { - from("build${sep}publications${sep}androidRelease") { - renameModule(name, "android", version = version) - } - from("build${sep}outputs${sep}aar") { - include("*-release*") - rename { - it.replace("-release", "-android-release") - } - } - from("build${sep}libs") { - include("*android*") - include("*androidRelease-javadoc*") - rename { - it.replace("androidRelease-javadoc", "android") - } - } - } - this.getByName("main").contents { - from("build${sep}publications${sep}kotlinMultiplatform") { - renameModule(name, version = version) - } - from("build${sep}kotlinToolingMetadata") - from("build${sep}libs") { - include("*compose-kotlin*") - include("*compose-metadata*") - rename { - it.replace("-kotlin", "") - .replace("-metadata", "") - .replace("Multiplatform-javadoc", "") - } - } - } - this.maybeCreate("desktop").contents { - // kotlin multiplatform modules - from("build${sep}publications${sep}desktop") { - renameModule(name, "desktop", version = version) - } - from("build${sep}libs") { - include("*desktop*") - include("*desktop-javadoc*") - rename { - it.replace("desktop-javadoc", "desktop") - } - } - } + getByName("main").contents { fromDistMaven(project, project.name) } + maybeCreate("android").contents { fromDistMaven(project, "${project.name}-android") } + maybeCreate("desktop").contents { fromDistMaven(project, "${project.name}-desktop") } // make other distZip tasks run together with the main distZip - val platformDists = project.tasks.filter { task -> - task.name.matches(Consts.taskRegex) - }.toTypedArray() + val platformDists = project.tasks.filter { it.name.matches(Regex("(.*)DistZip")) }.toTypedArray() project.tasks.getByName("distZip").finalizedBy(*platformDists) } fun DistributionContainer.configureForJvm(project: Project) { - val sep = File.separator - val version = project.versionName() - val name = project.name - - this.getByName("main").contents { - // non android modules - from("build${sep}libs") - from("build${sep}publications${sep}maven") { - renameModule(name, version = version) - } - // android modules - from("build${sep}outputs${sep}aar") { - include("*-release*") - } - from("build${sep}publications${sep}release") { - renameModule(name, version = version) - } - from("build${sep}intermediates${sep}java_doc_jar${sep}release") { - include("*javadoc*") - rename { it.replace("release", "$name-$version") } - } - from("build${sep}intermediates${sep}source_jar${sep}release") { - include("*sources*") - rename { it.replace("release", "$name-$version") } - } - } + getByName("main").contents { fromDistMaven(project, project.name) } } -private fun CopySpec.renameModule(projectName: String, renameTo: String = "", version: String) { - var target = "" - if (renameTo.isNotEmpty()) { - target = "-$renameTo" - } - rename { - it.replace("module.json", "$projectName$target-$version.module") +/** + * Copies one publication out of the project's Maven repository layout. Maven guarantees file names + * there (`-[-].`) independently of how the publish plugin + * names its tasks or intermediate outputs, which is exactly what craft expects. Only the few + * craft-specific names below need renaming. + */ +private fun CopySpec.fromDistMaven(project: Project, artifactId: String) { + val version = project.versionName() + val groupPath = project.group.toString().replace('.', '/') + from(project.distMavenDir().map { it.dir("$groupPath/$artifactId/$version") }) { + exclude("*.md5", "*.sha1", "*.sha256", "*.sha512", "*.asc") + rename { + when (it) { + // craft reads the POM from a fixed name + "$artifactId-$version.pom" -> "pom-default.xml" + // craft's android config maps - to -release.aar + "$artifactId-$version.aar" -> "$artifactId-release.aar" + // kept for parity with the old layout + "$artifactId-$version-kotlin-tooling-metadata.json" -> "kotlin-tooling-metadata.json" + else -> it + } + } } } From 8aa76d1699b21eee58cc064e3f2da65b4ab6908f Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Thu, 5 Nov 2026 10:27:42 +0100 Subject: [PATCH 2/2] ref(build): Make distMavenDir an extension property Co-Authored-By: Claude Opus 5.5 --- build.gradle.kts | 2 +- buildSrc/src/main/java/Publication.kt | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 7f4f96295b7..6a42fe07a42 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -133,7 +133,7 @@ subprojects { // the dist zips craft publishes are assembled from this, see Publication.kt maven { name = DIST_MAVEN_REPO - url = distMavenDir().get().asFile.toURI() + url = distMavenDir.get().asFile.toURI() } maven { name = "unityMaven" diff --git a/buildSrc/src/main/java/Publication.kt b/buildSrc/src/main/java/Publication.kt index aa73da0aec6..c9251fe25c0 100644 --- a/buildSrc/src/main/java/Publication.kt +++ b/buildSrc/src/main/java/Publication.kt @@ -1,6 +1,8 @@ import org.gradle.api.Project import org.gradle.api.distribution.DistributionContainer import org.gradle.api.file.CopySpec +import org.gradle.api.file.Directory +import org.gradle.api.provider.Provider /** * Name of the per-project Maven repository the dist zips are assembled from. @@ -8,7 +10,7 @@ import org.gradle.api.file.CopySpec */ const val DIST_MAVEN_REPO = "distMaven" -fun Project.distMavenDir() = layout.buildDirectory.dir(DIST_MAVEN_REPO) +val Project.distMavenDir: Provider get() = layout.buildDirectory.dir(DIST_MAVEN_REPO) private fun Project.versionName(): String = providers.gradleProperty("versionName").get() @@ -37,7 +39,7 @@ fun DistributionContainer.configureForJvm(project: Project) { private fun CopySpec.fromDistMaven(project: Project, artifactId: String) { val version = project.versionName() val groupPath = project.group.toString().replace('.', '/') - from(project.distMavenDir().map { it.dir("$groupPath/$artifactId/$version") }) { + from(project.distMavenDir.map { it.dir("$groupPath/$artifactId/$version") }) { exclude("*.md5", "*.sha1", "*.sha256", "*.sha512", "*.asc") rename { when (it) {