From 38589f04e4178b60a4a83b98493d14d29e466ed5 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Thu, 4 Jun 2026 21:27:12 +0100 Subject: [PATCH 01/23] First pass --- build.gradle | 720 +----------------- buildSrc/build.gradle | 10 + .../groovy/fabric-api.deprecated-bom.gradle | 32 + .../src/main/groovy/fabric-api.java.gradle | 16 + .../src/main/groovy/fabric-api.lint.gradle | 36 + .../src/main/groovy/fabric-api.loom.gradle | 33 + .../main/groovy/fabric-api.maven-bom.gradle | 30 + .../groovy/fabric-api.meta-publishing.gradle | 27 + .../src/main/groovy/fabric-api.module.gradle | 13 + .../main/groovy/fabric-api.publishing.gradle | 75 ++ .../src/main/groovy/fabric-api.root.gradle | 287 +++++++ .../src/main/groovy/fabric-api.testing.gradle | 92 +++ .../main/groovy/fabric-api.validation.gradle | 37 + .../groovy/fabric-api.version-catalog.gradle | 57 ++ .../main/groovy/fabric-api.versioning.gradle | 10 + .../fabric/build/BumpVersionTask.groovy | 33 +- .../fabric/build/FabricApiBuildUtils.groovy | 162 ++++ .../build/FabricApiModuleExtension.groovy | 97 +++ .../build/GeneratePackageInfosTask.groovy | 57 +- .../build/ValidateAnnotationsTask.groovy | 30 + .../fabric/build/ValidateModuleTask.groovy | 50 +- deprecated/build.gradle | 47 +- .../fabric-resource-loader-v0/build.gradle | 8 +- fabric-api-base/build.gradle | 6 +- fabric-api-bom/build.gradle | 30 +- fabric-api-catalog/build.gradle | 55 +- fabric-api-lookup-api-v1/build.gradle | 8 +- fabric-biome-api-v1/build.gradle | 6 +- fabric-block-api-v1/build.gradle | 6 +- fabric-block-getter-api-v2/build.gradle | 4 +- fabric-client-gametest-api-v1/build.gradle | 4 +- fabric-command-api-v2/build.gradle | 8 +- fabric-content-registries-v0/build.gradle | 6 +- fabric-convention-tags-v2/build.gradle | 8 +- fabric-crash-report-info-v1/build.gradle | 6 +- fabric-creative-tab-api-v1/build.gradle | 6 +- fabric-data-attachment-api-v1/build.gradle | 8 +- fabric-data-generation-api-v1/build.gradle | 8 +- fabric-debug-api-v1/build.gradle | 8 +- fabric-dimensions-v1/build.gradle | 8 +- fabric-entity-events-v1/build.gradle | 8 +- fabric-events-interaction-v0/build.gradle | 8 +- fabric-game-rule-api-v1/build.gradle | 8 +- fabric-gametest-api-v1/build.gradle | 6 +- fabric-item-api-v1/build.gradle | 8 +- fabric-key-mapping-api-v1/build.gradle | 6 +- fabric-lifecycle-events-v1/build.gradle | 6 +- fabric-loot-api-v3/build.gradle | 6 +- fabric-menu-api-v1/build.gradle | 8 +- fabric-message-api-v1/build.gradle | 8 +- fabric-model-loading-api-v1/build.gradle | 8 +- fabric-networking-api-v1/build.gradle | 8 +- fabric-object-builder-api-v1/build.gradle | 8 +- fabric-particles-v1/build.gradle | 8 +- fabric-permission-api-v1/build.gradle | 8 +- fabric-recipe-api-v1/build.gradle | 8 +- fabric-registry-sync-v0/build.gradle | 8 +- fabric-renderer-api-v1/build.gradle | 8 +- fabric-renderer-indigo/build.gradle | 6 +- fabric-rendering-fluids-v1/build.gradle | 6 +- fabric-rendering-v1/build.gradle | 8 +- .../build.gradle | 6 +- fabric-resource-loader-v1/build.gradle | 8 +- fabric-screen-api-v1/build.gradle | 6 +- fabric-serialization-api-v1/build.gradle | 4 +- fabric-sound-api-v1/build.gradle | 6 +- fabric-tag-api-v1/build.gradle | 8 +- fabric-transfer-api-v1/build.gradle | 8 +- .../build.gradle | 6 +- gradle/validate-annotations.gradle | 49 -- 70 files changed, 1298 insertions(+), 1103 deletions(-) create mode 100644 buildSrc/src/main/groovy/fabric-api.deprecated-bom.gradle create mode 100644 buildSrc/src/main/groovy/fabric-api.java.gradle create mode 100644 buildSrc/src/main/groovy/fabric-api.lint.gradle create mode 100644 buildSrc/src/main/groovy/fabric-api.loom.gradle create mode 100644 buildSrc/src/main/groovy/fabric-api.maven-bom.gradle create mode 100644 buildSrc/src/main/groovy/fabric-api.meta-publishing.gradle create mode 100644 buildSrc/src/main/groovy/fabric-api.module.gradle create mode 100644 buildSrc/src/main/groovy/fabric-api.publishing.gradle create mode 100644 buildSrc/src/main/groovy/fabric-api.root.gradle create mode 100644 buildSrc/src/main/groovy/fabric-api.testing.gradle create mode 100644 buildSrc/src/main/groovy/fabric-api.validation.gradle create mode 100644 buildSrc/src/main/groovy/fabric-api.version-catalog.gradle create mode 100644 buildSrc/src/main/groovy/fabric-api.versioning.gradle rename gradle/module-versioning.gradle => buildSrc/src/main/groovy/net/fabricmc/fabric/build/BumpVersionTask.groovy (67%) create mode 100644 buildSrc/src/main/groovy/net/fabricmc/fabric/build/FabricApiBuildUtils.groovy create mode 100644 buildSrc/src/main/groovy/net/fabricmc/fabric/build/FabricApiModuleExtension.groovy rename gradle/package-info.gradle => buildSrc/src/main/groovy/net/fabricmc/fabric/build/GeneratePackageInfosTask.groovy (54%) create mode 100644 buildSrc/src/main/groovy/net/fabricmc/fabric/build/ValidateAnnotationsTask.groovy rename gradle/module-validation.gradle => buildSrc/src/main/groovy/net/fabricmc/fabric/build/ValidateModuleTask.groovy (65%) delete mode 100644 gradle/validate-annotations.gradle diff --git a/build.gradle b/build.gradle index 4047642e2fe..c6fc6e5169f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,721 +1,7 @@ plugins { - id "java-library" id "eclipse" - id "maven-publish" - id "net.fabricmc.fabric-loom" version "1.16.2" apply false - id "com.diffplug.spotless" version "8.5.1" + id "com.diffplug.spotless" version "8.5.1" apply false id "me.modmuss50.remotesign" version "0.5.0" apply false - id "me.modmuss50.mod-publish-plugin" version "2.0.0-beta.1" + id "me.modmuss50.mod-publish-plugin" version "2.0.0-beta.1" apply false + id "fabric-api.root" } - -def branchProvider = providers.of(GitBranchValueSource.class) {} -version = project.version + "+" + (providers.environmentVariable("CI").present ? branchProvider.get().replace("/", "_") : "local") -logger.lifecycle("Building Fabric: " + version) - -def metaProjects = [ - 'deprecated', - 'fabric-api-bom', - 'fabric-api-catalog' -] - -def debugArgs = [ - "-enableassertions", - "-Dmixin.debug.verify=true", - //"-Dmixin.debug.strict=true", - "-Dmixin.debug.countInjections=true", - "-XX:+UseZGC", - "-XX:+UseCompactObjectHeaders", - "-XX:+AlwaysPreTouch", - "-XX:+UseStringDeduplication" -] - -import groovy.json.JsonSlurper -import org.apache.commons.codec.digest.DigestUtils -import net.fabricmc.fabric.impl.build.CommitHashValueSource -import net.fabricmc.fabric.impl.build.GitBranchValueSource -import java.net.http.HttpClient -import java.net.http.HttpRequest -import java.net.http.HttpResponse - -def getSubprojectVersion(Project project) { - // Get the version from the gradle.properties file - def version = project.properties["${project.name}-version"] - - if (!version) { - throw new NullPointerException("Could not find version for " + project.name) - } - - if (!project.providers.environmentVariable("CI").present) { - return version + "+local" - } - - def hashProvider = project.providers.of(CommitHashValueSource.class) { - parameters.directory = project.name - } - return version + "+" + hashProvider.get().substring(0, 8) + DigestUtils.sha256Hex(project.rootProject.minecraft_version).substring(0, 2) -} - -def moduleDependencies(project, List depNames) { - def deps = depNames.iterator().collect { project.dependencies.project(path: ":$it") } - def clientOutputs = depNames.iterator().collect { findProject(":$it").sourceSets.client.output } - - project.dependencies { - deps.each { - api it - } - - clientOutputs.each { - clientImplementation it - } - } - - def depNodes = deps.collect { - [ - groupId: it.group, - artifactId: it.name, - version: getSubprojectVersion(project.project(":" + it.name)), - scope: "compile" - ] - } - - // As we manually handle the maven artifacts, we need to also manually specify the deps. - project.publishing { - publications { - mavenJava(MavenPublication) { - pom.withXml { - def depsNode = asNode().appendNode("dependencies") - - for (def depNode in depNodes) { - def node = depsNode.appendNode("dependency") - - for (def entry in depNode) { - node.appendNode(entry.key, entry.value) - } - } - } - } - } - } -} - -def testDependencies(project, List depNames) { - def deps = depNames.iterator().collect { project.dependencies.project(path: ":$it") } - def clientOutputs = depNames.iterator().collect { findProject(":$it").sourceSets.client.output } - - project.dependencies { - deps.each { - testmodImplementation it - } - - clientOutputs.each { - testmodClientImplementation it - } - } -} - -allprojects { - group = "net.fabricmc.fabric-api" - - apply plugin: "maven-publish" - apply plugin: "me.modmuss50.remotesign" - - tasks.withType(GenerateModuleMetadata).configureEach { - enabled = false - } - - remoteSign { - requestUrl = providers.environmentVariable("SIGNING_SERVER") - pgpAuthKey = providers.environmentVariable("SIGNING_PGP_KEY") - jarAuthKey = providers.environmentVariable("SIGNING_JAR_KEY") - - useDummyForTesting = !providers.environmentVariable("SIGNING_SERVER").present - - afterEvaluate { - // PGP sign all maven publications. - sign publishing.publications.mavenJava - } - } - - publishing { - setupRepositories(repositories) - } - - if (metaProjects.contains(it.name)) { - return - } - - apply plugin: "java-library" - apply plugin: "checkstyle" - apply plugin: "net.fabricmc.fabric-loom" - apply plugin: "com.diffplug.spotless" - - tasks.withType(JavaCompile).configureEach { - it.options.release = 25 - } - - java { - // Must be added before the split source sets are setup. - withSourcesJar() - } - - loom { - splitEnvironmentSourceSets() - } - - sourceSets { - testmod { - compileClasspath += main.compileClasspath - runtimeClasspath += main.runtimeClasspath - } - - testmodClient { - compileClasspath += main.compileClasspath - runtimeClasspath += main.runtimeClasspath - compileClasspath += client.compileClasspath - runtimeClasspath += client.runtimeClasspath - - compileClasspath += testmod.compileClasspath - runtimeClasspath += testmod.runtimeClasspath - } - - test { - compileClasspath += testmodClient.compileClasspath - runtimeClasspath += testmodClient.runtimeClasspath - } - } - - loom { - runtimeOnlyLog4j = true - - runs { - testmodClient { - client() - ideConfigGenerated project.rootProject == project - name = "Testmod Client" - source sourceSets.testmodClient - } - testmodServer { - server() - ideConfigGenerated project.rootProject == project - name = "Testmod Server" - source sourceSets.testmod - } - } - } - - loom.runs.configureEach { - vmArgs(debugArgs) - } - - allprojects.each { p -> - if (metaProjects.contains(p.name)) { - return - } - - loom.mods.register(p.name) { - sourceSet p.sourceSets.main - sourceSet p.sourceSets.client - } - - loom.mods.register(p.name + "-testmod") { - sourceSet p.sourceSets.testmod - sourceSet p.sourceSets.testmodClient - } - } - - dependencies { - minecraft "com.mojang:minecraft:$rootProject.minecraft_version" - api "net.fabricmc:fabric-loader:${project.loader_version}" - - testmodImplementation sourceSets.main.output - testmodClientImplementation sourceSets.main.output - testmodClientImplementation sourceSets.client.output - testmodClientImplementation sourceSets.testmod.output - - testImplementation "net.fabricmc:fabric-loader-junit:${project.loader_version}" - testImplementation sourceSets.testmodClient.output - testImplementation 'org.mockito:mockito-core:5.23.0' - } - - test { - useJUnitPlatform() - jvmArgs(debugArgs) - } - - tasks.withType(ProcessResources).configureEach { - inputs.property "version", project.version - - filesMatching("fabric.mod.json") { - expand "version": inputs.properties.version - } - } - - spotless { - lineEndings = com.diffplug.spotless.LineEnding.UNIX - - java { - licenseHeaderFile(rootProject.file("HEADER")) - removeUnusedImports() - importOrder('java', 'javax', '', 'net.minecraft', 'net.fabricmc') - leadingSpacesToTabs() - trimTrailingWhitespace() - } - - // Sort the en_us translation files - // The other languages are handled by Crowdin - json { - target 'src/**/lang/en_us.json' - targetExclude 'src/**/generated/**' - gson().indentWithSpaces(2).sortByKeys() - } - } - - checkstyle { - configFile = rootProject.file("checkstyle.xml") - toolVersion = "13.3.0" - } - - tasks.withType(AbstractArchiveTask).configureEach { - preserveFileTimestamps = false - reproducibleFileOrder = true - } - - remoteSign { - sign jar - } - - // Run this task after updating minecraft to regenerate any required resources - tasks.register('generateResources') { - group = "fabric" - } - - tasks.register('testmodJar', Jar) { - from sourceSets.testmod.output - from sourceSets.testmodClient.output - archiveClassifier = "testmod" - } - - build.dependsOn testmodJar - - String archivesName = project.base.archivesName.get() - [jar, sourcesJar].each { - it.from(rootProject.file("LICENSE")) { - rename { "${it}-${archivesName}"} - } - } - - tasks.register('enigma', net.fabricmc.loom.task.tool.ModEnigmaTask) { - def clientOnly = file('src/client').exists() && !file('src/main').exists() - def dir = clientOnly ? file('src/client/resources') : file('src/main/resources') - mappingFile = new File(dir, project.name + '.mapping') - } - - tasks.register('validateMixinNames', net.fabricmc.loom.task.ValidateMixinNameTask) { - source(sourceSets.main.output) - source(sourceSets.client.output) - source(sourceSets.testmod.output) - outputs.upToDateWhen { true } // Task has no outputs - } - check.dependsOn "validateMixinNames" - - // Apply to each valid subproject. - apply from: rootProject.file('gradle/package-info.gradle') - apply from: rootProject.file('gradle/validate-annotations.gradle') -} - -def nestedTestModJars = project.files() - -subprojects { - if (metaProjects.contains(it.name) || !(it.file("src/testmod").exists() || it.file("src/testmodClient").exists())) { - return - } - - nestedTestModJars.from(it.tasks.named("testmodJar")) -} - -loom.nestJars(tasks.named("testmodJar"), nestedTestModJars) - -// Apply auxiliary buildscripts to submodules -// This must be done after all plugins are applied to subprojects -apply from: "gradle/module-validation.gradle" -apply from: "gradle/module-versioning.gradle" - -loom { - accessWidenerPath = file("gradle/javadoc.classtweaker") -} - -javadoc { - options { - source = "25" - encoding = "UTF-8" - charSet = "UTF-8" - memberLevel = JavadocMemberLevel.PACKAGE - addStringOption("Xdoclint:all,-missing", "-quiet") - addBooleanOption("-syntax-highlight", true) - - tags( - 'apiNote:a:API Note:', - 'implSpec:a:Implementation Requirements:', - 'implNote:a:Implementation Note:' - ) - } - - allprojects.each { - if (metaProjects.contains(it.name)) { - return - } - - source(it.sourceSets.main.allJava) - source(it.sourceSets.client.allJava) - } - - classpath = files(sourceSets.main.compileClasspath, sourceSets.client.compileClasspath) - include("**/api/**") - failOnError = true -} - -tasks.register('javadocJar', Jar) { - dependsOn javadoc - from javadoc.destinationDir - //Set as `fatjavadoc` to prevent an ide form trying to use this javadoc, over using the modules javadoc - archiveClassifier = "fatjavadoc" -} - -build.dependsOn javadocJar - -loom { - runs { - gametest { - inherit testmodServer - - name "Game Test" - - // Enable the gametest runner - vmArg "-Dfabric-api.gametest" - vmArg "-Dfabric-api.gametest.report-file=${project.layout.buildDirectory.file("junit.xml").get().getAsFile()}" - runDir "build/gametest" - } - autoTestServer { - inherit testmodServer - name "Auto Test Server" - vmArg "-Dfabric.autoTest" - } - clientGametest { - inherit testmodClient - name "Client Game Test" - vmArg "-Dfabric.client.gametest" - vmArg "-Dfabric-tag-conventions-v2.missingTagTranslationWarning=fail" - vmArg "-Dfabric-tag-conventions-v1.legacyTagWarning=fail" - } - } -} - -runGametest { - outputs.file project.layout.buildDirectory.file("junit.xml") -} - -// Format all the gradle files -spotless { - groovyGradle { - target 'src/**/*.gradle', '*.gradle', 'gradle/*.gradle' - greclipse() - } -} - -def addPomMetadataInformation(Project project, MavenPom pom) { - def modJsonFile = project.file("src/main/resources/fabric.mod.json") - - if (!modJsonFile.exists()) { - modJsonFile = project.file("src/client/resources/fabric.mod.json") - } - - def modJson = new JsonSlurper().parse(modJsonFile) - pom.name = modJson.name - pom.url = "https://github.com/FabricMC/fabric/tree/HEAD/${project.rootDir.relativePath(project.projectDir)}" - pom.description = modJson.description - pom.licenses { - license { - name = "Apache-2.0" - url = "https://github.com/FabricMC/fabric/blob/HEAD/LICENSE" - } - } - pom.developers { - developer { - name = "FabricMC" - url = "https://fabricmc.net/" - } - } - pom.scm { - connection = "scm:git:https://github.com/FabricMC/fabric.git" - url = "https://github.com/FabricMC/fabric" - developerConnection = "scm:git:git@github.com:FabricMC/fabric.git" - } - pom.issueManagement { - system = "GitHub" - url = "https://github.com/FabricMC/fabric/issues" - } -} - -subprojects { - if (metaProjects.contains(it.name)) { - return - } - - base { - archivesName = project.name - } - - dependencies { - testmodImplementation sourceSets.main.output - - // Make all modules depend on the gametest api (and thus res loader) to try and promote its usage. - if (project.name != "fabric-gametest-api-v1") { - testmodImplementation project(path: ':fabric-gametest-api-v1') - testmodClientImplementation this.project(":fabric-gametest-api-v1").sourceSets.client.output - testmodImplementation project(path: ':fabric-resource-loader-v1') - testmodClientImplementation this.project(":fabric-resource-loader-v1").sourceSets.client.output - } - - // Make all testmods run with registry-sync-v0 as it is required to register new objects. - if (project.name != "fabric-registry-sync-v0") { - testmodRuntimeOnly project(path: ':fabric-registry-sync-v0') - testmodClientImplementation this.project(":fabric-registry-sync-v0").sourceSets.client.output - } - } - - publishing { - publications { - mavenJava(MavenPublication) { - pom { - addPomMetadataInformation(project, pom) - } - artifact(tasks.jar.archiveFile) { - builtBy(tasks.jar) - } - - artifact(tasks.sourcesJar) { - builtBy tasks.sourcesJar - } - } - } - } - - def projectName = it.name - def projectVersion = getSubprojectVersion(it) - - // Skip publishing if the artifact already exists on the maven server - tasks.withType(PublishToMavenRepository).configureEach { - onlyIf { - if (!providers.environmentVariable("MAVEN_URL").present) { - // Always try to publish if the maven url is not set (e.g locally) - return true - } - - def artifactPath = "https://maven.fabricmc.net/net/fabricmc/fabric-api/${projectName}/${projectVersion}/${projectName}-${projectVersion}.pom" - - boolean exists = HttpClient.newHttpClient().withCloseable { client -> - def request = HttpRequest.newBuilder() - .uri(URI.create(artifactPath)) - .method("HEAD", HttpRequest.BodyPublishers.noBody()) - .build() - - def response = client.send(request, HttpResponse.BodyHandlers.discarding()) - response.statusCode() == 200 - } - - if (exists) { - logger.lifecycle("${projectName}-${projectVersion}.pom has already been published") - } else { - logger.lifecycle("${projectName}-${projectVersion}.pom does not exist, publishing") - } - - return !exists - } - } - - // We manually handle the pom generation - loom.disableDeprecatedPomGeneration(publishing.publications.mavenJava) - - javadoc.enabled = false -} - -publishing { - publications { - mavenJava(MavenPublication) { - artifact(signJar.output) { - builtBy(signJar) - } - - artifact(sourcesJar) { - builtBy sourcesJar - } - - artifact javadocJar - artifact testmodJar - - pom { - addPomMetadataInformation(rootProject, pom) - } - - List> dependencies = [] - - subprojects.each { - // The maven BOM containing all of the deprecated modules is added manually below. - if (it.path.startsWith(":deprecated") || metaProjects.contains(it.name)) { - return - } - - dependencies.add([ - 'groupId': it.group, - 'artifactId': it.name, - 'version': getSubprojectVersion(it), - 'scope': 'compile' - ]) - } - - def thisGroup = group - def thisVersion = version - - pom.withXml { - def depsNode = asNode().appendNode("dependencies") - for (dep in dependencies) { - def depNode = depsNode.appendNode("dependency") - depNode.appendNode("groupId", dep['groupId']) - depNode.appendNode("artifactId", dep['artifactId']) - depNode.appendNode("version", dep['version']) - depNode.appendNode("scope", dep['scope']) - } - - // Depend on the deprecated BOM to allow opting out of deprecated modules. - def depNode = depsNode.appendNode("dependency") - depNode.appendNode("groupId", thisGroup) - depNode.appendNode("artifactId", "fabric-api-deprecated") - depNode.appendNode("version", thisVersion) - depNode.appendNode("scope", "compile") - } - } - } -} - -// Required until the deprecation is removed. Fabric API's main jar that is published to maven does not contain sub modules. -loom.disableDeprecatedPomGeneration(publishing.publications.mavenJava) - -void setupRepositories(RepositoryHandler repositories) { - //repositories.mavenLocal() // uncomment for testing - if (providers.environmentVariable("MAVEN_URL").present) { - repositories.maven { - url = providers.environmentVariable("MAVEN_URL") - credentials { - username = providers.environmentVariable("MAVEN_USERNAME").get() - password = providers.environmentVariable("MAVEN_PASSWORD").get() - } - } - } -} - -// These modules are not included in the fat jar, maven will resolve them via the pom. -def devOnlyModules = [ - "fabric-client-gametest-api-v1", - "fabric-gametest-api-v1", -] - -dependencies { - subprojects.each { - if (metaProjects.contains(it.name)) { - return - } - - api project(path: "${it.path}") - clientImplementation this.project("${it.path}:").sourceSets.client.output - - testmodImplementation this.project("${it.path}:").sourceSets.testmod.output - testmodClientImplementation this.project("${it.path}:").sourceSets.testmodClient.output - } -} - -configurations { - nestedJars { - transitive = false - } -} - -dependencies { - subprojects.each { - if (it.name in devOnlyModules || metaProjects.contains(it.name)) { - return - } - - nestedJars project("${it.path}") - } -} - -loom.nestJars(tasks.named("jar"), configurations.nestedJars) - -// Attempt to create a single jar with all files from all nested jars, this will fail if there are duplicate files. -tasks.register("checkNoDuplicateFiles", Zip) { - inputs.files configurations.nestedJars - destinationDirectory = layout.buildDirectory.dir("test") - - from { - configurations.nestedJars.files.collect { zipTree(it) } - } - - // We expect these files to be duplicated, so exclude them. - exclude 'META-INF/**' - exclude 'fabric.mod.json' -} - -check.dependsOn "checkNoDuplicateFiles" - -publishMods { - file = signJar.output - changelog = providers.environmentVariable("CHANGELOG").getOrElse("No changelog provided") - type = project.prerelease == "true" ? BETA : STABLE - displayName = "[${project.minecraft_version}] Fabric API $project.version" - modLoaders.add("fabric") - dryRun = providers.environmentVariable("CURSEFORGE_API_KEY").getOrNull() == null - - curseforge { - accessToken = providers.environmentVariable("CURSEFORGE_API_KEY") - projectId = "306612" - project.curseforge_minecraft_versions.split(",").each { minecraftVersions.add(it.trim()) } - } - - modrinth { - accessToken = providers.environmentVariable("MODRINTH_TOKEN") - projectId = "P7dR8mSH" - minecraftVersions.add(project.minecraft_version) - if (project.modrinth_extra_minecraft_versions) { - project.modrinth_extra_minecraft_versions.split(",").each { minecraftVersions.add(it.trim()) } - } - } - - github { - accessToken = providers.environmentVariable("GITHUB_TOKEN") - repository = providers.environmentVariable("GITHUB_REPOSITORY").getOrElse("FabricMC/dryrun") - commitish = providers.environmentVariable("GITHUB_REF_NAME").getOrElse("dryrun") - } -} - -assemble.dependsOn signJar - -// Copy the final jar into a directory of its own so we can easily upload it without zipping during github actions builds. -tasks.register('outJar', Copy) { - from signJar.output - into layout.buildDirectory.dir("out") -} - -// A task to ensure that the version being released has not already been released. -tasks.register('checkVersion') { - doFirst { - def xml = new URL("https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api/maven-metadata.xml").text - def metadata = new groovy.xml.XmlSlurper().parseText(xml) - def versions = metadata.versioning.versions.version*.text(); - if (versions.contains(version)) { - throw new RuntimeException("${version} has already been released!") - } - } -} - -tasks.publishMods.dependsOn checkVersion -publish.mustRunAfter checkVersion diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index aabaea66a72..a25afd1f9d2 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -1,12 +1,22 @@ plugins { + id 'groovy-gradle-plugin' id 'checkstyle' id "com.diffplug.spotless" version "6.20.0" } repositories { + maven { + name = 'Fabric' + url = 'https://maven.fabricmc.net/' + } + gradlePluginPortal() mavenCentral() } +dependencies { + implementation "net.fabricmc:fabric-loom:1.16.2" +} + checkstyle { configFile = file("../checkstyle.xml") toolVersion = "10.20.2" diff --git a/buildSrc/src/main/groovy/fabric-api.deprecated-bom.gradle b/buildSrc/src/main/groovy/fabric-api.deprecated-bom.gradle new file mode 100644 index 00000000000..9ace1713694 --- /dev/null +++ b/buildSrc/src/main/groovy/fabric-api.deprecated-bom.gradle @@ -0,0 +1,32 @@ +import net.fabricmc.fabric.build.FabricApiBuildUtils +import org.gradle.api.publish.maven.MavenPublication + +plugins { + id "fabric-api.meta-publishing" +} + +version = rootProject.version + +publishing { + publications { + mavenJava(MavenPublication) { + artifactId = 'fabric-api-deprecated' + + pom.withXml { + def depsNode = asNode().appendNode("dependencies") + + rootProject.allprojects.each { + if (it.name == "deprecated" || !it.path.startsWith(":deprecated")) { + return + } + + def depNode = depsNode.appendNode("dependency") + depNode.appendNode("groupId", it.group) + depNode.appendNode("artifactId", it.name) + depNode.appendNode("version", FabricApiBuildUtils.moduleVersion(it)) + depNode.appendNode("scope", "compile") + } + } + } + } +} diff --git a/buildSrc/src/main/groovy/fabric-api.java.gradle b/buildSrc/src/main/groovy/fabric-api.java.gradle new file mode 100644 index 00000000000..ca146cf2515 --- /dev/null +++ b/buildSrc/src/main/groovy/fabric-api.java.gradle @@ -0,0 +1,16 @@ +plugins { + id "java-library" +} + +tasks.withType(JavaCompile).configureEach { + it.options.release = 25 +} + +java { + withSourcesJar() +} + +tasks.withType(AbstractArchiveTask).configureEach { + preserveFileTimestamps = false + reproducibleFileOrder = true +} diff --git a/buildSrc/src/main/groovy/fabric-api.lint.gradle b/buildSrc/src/main/groovy/fabric-api.lint.gradle new file mode 100644 index 00000000000..89845c05c3f --- /dev/null +++ b/buildSrc/src/main/groovy/fabric-api.lint.gradle @@ -0,0 +1,36 @@ +plugins { + id "checkstyle" + id "com.diffplug.spotless" +} + +checkstyle { + configFile = rootProject.file("checkstyle.xml") + toolVersion = "13.3.0" +} + +spotless { + lineEndings = 'UNIX' + + java { + licenseHeaderFile(rootProject.file("HEADER")) + removeUnusedImports() + importOrder('java', 'javax', '', 'net.minecraft', 'net.fabricmc') + leadingSpacesToTabs() + trimTrailingWhitespace() + } + + json { + target 'src/**/lang/en_us.json' + targetExclude 'src/**/generated/**' + gson().indentWithSpaces(2).sortByKeys() + } +} + +if (project == rootProject) { + spotless { + groovyGradle { + target 'src/**/*.gradle', '*.gradle', 'gradle/*.gradle' + greclipse() + } + } +} diff --git a/buildSrc/src/main/groovy/fabric-api.loom.gradle b/buildSrc/src/main/groovy/fabric-api.loom.gradle new file mode 100644 index 00000000000..3874694599b --- /dev/null +++ b/buildSrc/src/main/groovy/fabric-api.loom.gradle @@ -0,0 +1,33 @@ +import net.fabricmc.loom.task.tool.ModEnigmaTask + +plugins { + id "net.fabricmc.fabric-loom" +} + +loom { + splitEnvironmentSourceSets() + runtimeOnlyLog4j = true +} + +dependencies { + minecraft "com.mojang:minecraft:$rootProject.minecraft_version" + api "net.fabricmc:fabric-loader:${project.loader_version}" +} + +tasks.withType(ProcessResources).configureEach { + inputs.property "version", project.version + + filesMatching("fabric.mod.json") { + expand "version": inputs.properties.version + } +} + +tasks.register('generateResources') { + group = "fabric" +} + +tasks.register('enigma', ModEnigmaTask) { + def clientOnly = file('src/client').exists() && !file('src/main').exists() + def dir = clientOnly ? file('src/client/resources') : file('src/main/resources') + mappingFile = new File(dir, project.name + '.mapping') +} diff --git a/buildSrc/src/main/groovy/fabric-api.maven-bom.gradle b/buildSrc/src/main/groovy/fabric-api.maven-bom.gradle new file mode 100644 index 00000000000..9303cee7b4c --- /dev/null +++ b/buildSrc/src/main/groovy/fabric-api.maven-bom.gradle @@ -0,0 +1,30 @@ +import org.gradle.api.publish.maven.MavenPublication + +plugins { + id "java-platform" + id "fabric-api.meta-publishing" +} + +version = rootProject.version + +publishing.publications { + register('mavenJava', MavenPublication) { + from(components['javaPlatform']) + } +} + +tasks.withType(GenerateModuleMetadata).configureEach { + enabled = true +} + +dependencies { + constraints { + for (proj in rootProject.allprojects) { + if (proj == project || proj.name == 'fabric-api-catalog') { + continue + } + + api(project(proj.path)) + } + } +} diff --git a/buildSrc/src/main/groovy/fabric-api.meta-publishing.gradle b/buildSrc/src/main/groovy/fabric-api.meta-publishing.gradle new file mode 100644 index 00000000000..c07302620b8 --- /dev/null +++ b/buildSrc/src/main/groovy/fabric-api.meta-publishing.gradle @@ -0,0 +1,27 @@ +import net.fabricmc.fabric.build.FabricApiBuildUtils + +plugins { + id "maven-publish" + id "me.modmuss50.remotesign" +} + +group = "net.fabricmc.fabric-api" + +tasks.withType(GenerateModuleMetadata).configureEach { + enabled = false +} + +remoteSign { + requestUrl = providers.environmentVariable("SIGNING_SERVER") + pgpAuthKey = providers.environmentVariable("SIGNING_PGP_KEY") + jarAuthKey = providers.environmentVariable("SIGNING_JAR_KEY") + useDummyForTesting = !providers.environmentVariable("SIGNING_SERVER").present + + afterEvaluate { + sign publishing.publications.mavenJava + } +} + +publishing { + FabricApiBuildUtils.setupRepositories(project, repositories) +} diff --git a/buildSrc/src/main/groovy/fabric-api.module.gradle b/buildSrc/src/main/groovy/fabric-api.module.gradle new file mode 100644 index 00000000000..047799a19d2 --- /dev/null +++ b/buildSrc/src/main/groovy/fabric-api.module.gradle @@ -0,0 +1,13 @@ +import net.fabricmc.fabric.build.FabricApiModuleExtension + +plugins { + id "fabric-api.versioning" + id "fabric-api.java" + id "fabric-api.lint" + id "fabric-api.loom" + id "fabric-api.testing" + id "fabric-api.validation" + id "fabric-api.publishing" +} + +extensions.create("fabricApiModule", FabricApiModuleExtension, project) diff --git a/buildSrc/src/main/groovy/fabric-api.publishing.gradle b/buildSrc/src/main/groovy/fabric-api.publishing.gradle new file mode 100644 index 00000000000..b8ce575ebb8 --- /dev/null +++ b/buildSrc/src/main/groovy/fabric-api.publishing.gradle @@ -0,0 +1,75 @@ +import net.fabricmc.fabric.build.FabricApiBuildUtils +import org.gradle.api.publish.maven.MavenPublication + +plugins { + id "maven-publish" + id "me.modmuss50.remotesign" +} + +group = "net.fabricmc.fabric-api" +base { + archivesName = project.name +} + +tasks.withType(GenerateModuleMetadata).configureEach { + enabled = false +} + +remoteSign { + requestUrl = providers.environmentVariable("SIGNING_SERVER") + pgpAuthKey = providers.environmentVariable("SIGNING_PGP_KEY") + jarAuthKey = providers.environmentVariable("SIGNING_JAR_KEY") + useDummyForTesting = !providers.environmentVariable("SIGNING_SERVER").present + + afterEvaluate { + sign publishing.publications.mavenJava + } +} + +publishing { + FabricApiBuildUtils.setupRepositories(project, repositories) + + publications { + mavenJava(MavenPublication) { + pom { + FabricApiBuildUtils.addPomMetadataInformation(project, pom) + } + artifact(tasks.jar.archiveFile) { + builtBy(tasks.jar) + } + artifact(tasks.sourcesJar) { + builtBy tasks.sourcesJar + } + } + } +} + +remoteSign { + sign jar +} + +String archivesName = project.base.archivesName.get() +[jar, sourcesJar].each { + it.from(rootProject.file("LICENSE")) { + rename { "${it}-${archivesName}" } + } +} + +tasks.withType(PublishToMavenRepository).configureEach { + onlyIf { + def projectName = project.name + def projectVersion = project.version.toString() + def exists = FabricApiBuildUtils.publishedArtifactExists(project, projectName, projectVersion) + + if (exists) { + logger.lifecycle("${projectName}-${projectVersion}.pom has already been published") + } else if (providers.environmentVariable("MAVEN_URL").present) { + logger.lifecycle("${projectName}-${projectVersion}.pom does not exist, publishing") + } + + return !exists + } +} + +loom.disableDeprecatedPomGeneration(publishing.publications.mavenJava) +javadoc.enabled = false diff --git a/buildSrc/src/main/groovy/fabric-api.root.gradle b/buildSrc/src/main/groovy/fabric-api.root.gradle new file mode 100644 index 00000000000..01dd5df4033 --- /dev/null +++ b/buildSrc/src/main/groovy/fabric-api.root.gradle @@ -0,0 +1,287 @@ +import groovy.xml.XmlSlurper +import net.fabricmc.fabric.build.FabricApiBuildUtils +import org.gradle.api.publish.maven.MavenPublication +import org.gradle.external.javadoc.JavadocMemberLevel + +plugins { + id "fabric-api.module" + id "me.modmuss50.mod-publish-plugin" +} + +if (!file("src/client/java").exists()) { + tasks.named("compileClientJava", JavaCompile) { + classpath = files() + } +} + +if (!file("src/testmod/java").exists()) { + tasks.named("compileTestmodJava", JavaCompile) { + classpath = files() + } +} + +if (!file("src/testmodClient/java").exists()) { + tasks.named("compileTestmodClientJava", JavaCompile) { + classpath = files() + } +} + +tasks.named("validateModules") { + enabled = false +} + +loom { + accessWidenerPath = file("gradle/javadoc.classtweaker") + + runs { + gametest { + inherit testmodServer + name "Game Test" + vmArg "-Dfabric-api.gametest" + vmArg "-Dfabric-api.gametest.report-file=${project.layout.buildDirectory.file("junit.xml").get().getAsFile()}" + runDir "build/gametest" + } + autoTestServer { + inherit testmodServer + name "Auto Test Server" + vmArg "-Dfabric.autoTest" + } + clientGametest { + inherit testmodClient + name "Client Game Test" + vmArg "-Dfabric.client.gametest" + vmArg "-Dfabric-tag-conventions-v2.missingTagTranslationWarning=fail" + vmArg "-Dfabric-tag-conventions-v1.legacyTagWarning=fail" + } + } +} + +runGametest { + outputs.file project.layout.buildDirectory.file("junit.xml") +} + +javadoc { + enabled = true + + options { + source = "25" + encoding = "UTF-8" + charSet = "UTF-8" + memberLevel = JavadocMemberLevel.PACKAGE + addStringOption("Xdoclint:all,-missing", "-quiet") + addBooleanOption("-syntax-highlight", true) + + tags( + 'apiNote:a:API Note:', + 'implSpec:a:Implementation Requirements:', + 'implNote:a:Implementation Note:' + ) + } + + include("**/api/**") + failOnError = true +} + +tasks.register('javadocJar', Jar) { + dependsOn javadoc + from javadoc.destinationDir + archiveClassifier = "fatjavadoc" +} + +build.dependsOn javadocJar + +configurations { + nestedJars { + transitive = false + } +} + +def includedModuleProjects = rootProject.allprojects.findAll { + FabricApiBuildUtils.isFabricModule(it) && it != project +} + +dependencies { + for (def moduleProject : includedModuleProjects) { + api project(path: moduleProject.path) + + if (!FabricApiBuildUtils.DEV_ONLY_MODULES.contains(moduleProject.name)) { + nestedJars project(moduleProject.path) + } + } +} + +for (def moduleProject : includedModuleProjects) { + moduleProject.pluginManager.withPlugin("fabric-api.module") { + dependencies { + clientImplementation moduleProject.sourceSets.client.output + testmodImplementation moduleProject.sourceSets.testmod.output + testmodClientImplementation moduleProject.sourceSets.testmodClient.output + } + } +} + +loom.nestJars(tasks.named("jar"), configurations.nestedJars) + +tasks.register("checkNoDuplicateFiles", Zip) { + inputs.files configurations.nestedJars + destinationDirectory = layout.buildDirectory.dir("test") + + from { + configurations.nestedJars.files.collect { zipTree(it) } + } + + exclude 'META-INF/**' + exclude 'fabric.mod.json' +} + +check.dependsOn "checkNoDuplicateFiles" + +publishing { + publications { + mavenJava(MavenPublication) { + artifact(signJar.output) { + builtBy(signJar) + } + + artifact(sourcesJar) { + builtBy sourcesJar + } + + artifact javadocJar + artifact testmodJar + + pom { + FabricApiBuildUtils.addPomMetadataInformation(rootProject, pom) + } + } + } +} + +loom.disableDeprecatedPomGeneration(publishing.publications.mavenJava) + +publishMods { + file = signJar.output + changelog = providers.environmentVariable("CHANGELOG").getOrElse("No changelog provided") + type = project.prerelease == "true" ? BETA : STABLE + displayName = "[${project.minecraft_version}] Fabric API $project.version" + modLoaders.add("fabric") + dryRun = providers.environmentVariable("CURSEFORGE_API_KEY").getOrNull() == null + + curseforge { + accessToken = providers.environmentVariable("CURSEFORGE_API_KEY") + projectId = "306612" + project.curseforge_minecraft_versions.split(",").each { minecraftVersions.add(it.trim()) } + } + + modrinth { + accessToken = providers.environmentVariable("MODRINTH_TOKEN") + projectId = "P7dR8mSH" + minecraftVersions.add(project.minecraft_version) + if (project.modrinth_extra_minecraft_versions) { + project.modrinth_extra_minecraft_versions.split(",").each { minecraftVersions.add(it.trim()) } + } + } + + github { + accessToken = providers.environmentVariable("GITHUB_TOKEN") + repository = providers.environmentVariable("GITHUB_REPOSITORY").getOrElse("FabricMC/dryrun") + commitish = providers.environmentVariable("GITHUB_REF_NAME").getOrElse("dryrun") + } +} + +assemble.dependsOn signJar + +tasks.register('outJar', Copy) { + from signJar.output + into layout.buildDirectory.dir("out") +} + +tasks.register('checkVersion') { + doFirst { + def xml = new URL("https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api/maven-metadata.xml").text + def metadata = new XmlSlurper().parseText(xml) + def versions = metadata.versioning.versions.version*.text() + if (versions.contains(version)) { + throw new RuntimeException("${version} has already been released!") + } + } +} + +tasks.publishMods.dependsOn checkVersion +publish.mustRunAfter checkVersion + +gradle.projectsEvaluated { + for (def moduleProject : includedModuleProjects) { + loom.mods.register(moduleProject.name) { + sourceSet moduleProject.sourceSets.main + sourceSet moduleProject.sourceSets.client + } + + loom.mods.register(moduleProject.name + "-testmod") { + sourceSet moduleProject.sourceSets.testmod + sourceSet moduleProject.sourceSets.testmodClient + } + } + + def nestedTestModJars = project.files() + for (def moduleProject : includedModuleProjects) { + if (!(moduleProject.file("src/testmod").exists() || moduleProject.file("src/testmodClient").exists())) { + continue + } + + nestedTestModJars.from(moduleProject.tasks.named("testmodJar")) + } + loom.nestJars(tasks.named("testmodJar"), nestedTestModJars) + + for (def moduleProject : includedModuleProjects) { + javadoc.source(moduleProject.sourceSets.main.allJava) + javadoc.source(moduleProject.sourceSets.client.allJava) + } + javadoc.dependsOn(includedModuleProjects.collect { it.tasks.named("classes") }) + javadoc.dependsOn(includedModuleProjects.collect { it.tasks.named("clientClasses") }) + javadoc.classpath = files( + sourceSets.main.compileClasspath, + sourceSets.client.compileClasspath, + includedModuleProjects.collect { it.layout.buildDirectory.dir("classes/java/main") }, + includedModuleProjects.collect { it.layout.buildDirectory.dir("classes/java/client") }, + includedModuleProjects.collect { it.layout.buildDirectory.dir("resources/main") }, + includedModuleProjects.collect { it.layout.buildDirectory.dir("resources/client") } + ) + + publishing.publications.mavenJava { + def dependencies = [] + + for (def moduleProject : includedModuleProjects) { + if (moduleProject.path.startsWith(":deprecated")) { + continue + } + + dependencies.add([ + 'groupId': moduleProject.group, + 'artifactId': moduleProject.name, + 'version': FabricApiBuildUtils.moduleVersion(moduleProject), + 'scope': 'compile' + ]) + } + + def thisGroup = group + def thisVersion = version + + pom.withXml { + def depsNode = asNode().appendNode("dependencies") + for (dep in dependencies) { + def depNode = depsNode.appendNode("dependency") + depNode.appendNode("groupId", dep['groupId']) + depNode.appendNode("artifactId", dep['artifactId']) + depNode.appendNode("version", dep['version']) + depNode.appendNode("scope", dep['scope']) + } + + def depNode = depsNode.appendNode("dependency") + depNode.appendNode("groupId", thisGroup) + depNode.appendNode("artifactId", "fabric-api-deprecated") + depNode.appendNode("version", thisVersion) + depNode.appendNode("scope", "compile") + } + } +} diff --git a/buildSrc/src/main/groovy/fabric-api.testing.gradle b/buildSrc/src/main/groovy/fabric-api.testing.gradle new file mode 100644 index 00000000000..c595c43b7d2 --- /dev/null +++ b/buildSrc/src/main/groovy/fabric-api.testing.gradle @@ -0,0 +1,92 @@ +import net.fabricmc.fabric.build.FabricApiBuildUtils +import net.fabricmc.loom.task.ValidateMixinNameTask + +sourceSets { + testmod { + compileClasspath += main.compileClasspath + runtimeClasspath += main.runtimeClasspath + } + + testmodClient { + compileClasspath += main.compileClasspath + runtimeClasspath += main.runtimeClasspath + compileClasspath += client.compileClasspath + runtimeClasspath += client.runtimeClasspath + + compileClasspath += testmod.compileClasspath + runtimeClasspath += testmod.runtimeClasspath + } + + test { + compileClasspath += testmodClient.compileClasspath + runtimeClasspath += testmodClient.runtimeClasspath + } +} + +loom { + runs { + testmodClient { + client() + ideConfigGenerated project.rootProject == project + name = "Testmod Client" + source sourceSets.testmodClient + } + testmodServer { + server() + ideConfigGenerated project.rootProject == project + name = "Testmod Server" + source sourceSets.testmod + } + } +} + +loom.runs.configureEach { + vmArgs(FabricApiBuildUtils.DEBUG_ARGS) +} + +dependencies { + testmodImplementation sourceSets.main.output + testmodClientImplementation sourceSets.main.output + testmodClientImplementation sourceSets.client.output + testmodClientImplementation sourceSets.testmod.output + + testImplementation "net.fabricmc:fabric-loader-junit:${project.loader_version}" + testImplementation sourceSets.testmodClient.output + testImplementation 'org.mockito:mockito-core:5.23.0' +} + +test { + useJUnitPlatform() + jvmArgs(FabricApiBuildUtils.DEBUG_ARGS) +} + +tasks.register('testmodJar', Jar) { + from sourceSets.testmod.output + from sourceSets.testmodClient.output + archiveClassifier = "testmod" +} + +build.dependsOn testmodJar + +tasks.register('validateMixinNames', ValidateMixinNameTask) { + source(sourceSets.main.output) + source(sourceSets.client.output) + source(sourceSets.testmod.output) + outputs.upToDateWhen { true } +} + +check.dependsOn "validateMixinNames" + +dependencies { + if (project.name != "fabric-gametest-api-v1" && rootProject.findProject(":fabric-gametest-api-v1") != null) { + testmodImplementation project(path: ':fabric-gametest-api-v1') + testmodClientImplementation rootProject.project(":fabric-gametest-api-v1").sourceSets.client.output + testmodImplementation project(path: ':fabric-resource-loader-v1') + testmodClientImplementation rootProject.project(":fabric-resource-loader-v1").sourceSets.client.output + } + + if (project.name != "fabric-registry-sync-v0" && rootProject.findProject(":fabric-registry-sync-v0") != null) { + testmodRuntimeOnly project(path: ':fabric-registry-sync-v0') + testmodClientImplementation rootProject.project(":fabric-registry-sync-v0").sourceSets.client.output + } +} diff --git a/buildSrc/src/main/groovy/fabric-api.validation.gradle b/buildSrc/src/main/groovy/fabric-api.validation.gradle new file mode 100644 index 00000000000..83d88458593 --- /dev/null +++ b/buildSrc/src/main/groovy/fabric-api.validation.gradle @@ -0,0 +1,37 @@ +import net.fabricmc.fabric.build.GeneratePackageInfosTask +import net.fabricmc.fabric.build.ValidateAnnotationsTask +import net.fabricmc.fabric.build.ValidateModuleTask + +tasks.register("validateModules", ValidateModuleTask) +tasks.check.dependsOn("validateModules") + +tasks.register('validateAnnotations', ValidateAnnotationsTask) { + group = 'fabric' + description = "Validate annotations used in Fabric API code." + outputs.upToDateWhen { true } + + source file("src/client/java") + source file("src/main/java") + source file("src/testmod/java") + source file("src/testmodClient/java") +} +tasks.check.dependsOn "validateAnnotations" + +for (def sourceSet in [sourceSets.main, sourceSets.client]) { + def sourceSetName = sourceSet.name + def taskName = sourceSet.getTaskName('generate', 'PackageInfos') + def task = tasks.register(taskName, GeneratePackageInfosTask) { + group = 'fabric' + description = "Generates package-info files for $sourceSetName packages." + sourceRoot = file("src/$sourceSetName/java") + header = rootProject.file('HEADER') + outputDir = file("src/generated/$sourceSetName") + } + sourceSet.java.srcDir task + + def cleanTask = tasks.register(sourceSet.getTaskName('clean', 'PackageInfos'), Delete) { + group = 'fabric' + delete file("src/generated/$sourceSetName") + } + clean.dependsOn cleanTask +} diff --git a/buildSrc/src/main/groovy/fabric-api.version-catalog.gradle b/buildSrc/src/main/groovy/fabric-api.version-catalog.gradle new file mode 100644 index 00000000000..6ba82d7bb23 --- /dev/null +++ b/buildSrc/src/main/groovy/fabric-api.version-catalog.gradle @@ -0,0 +1,57 @@ +import org.gradle.api.publish.maven.MavenPublication + +plugins { + id "version-catalog" + id "fabric-api.meta-publishing" +} + +version = rootProject.version + +publishing.publications { + register('mavenJava', MavenPublication) { + from components.versionCatalog + } +} + +tasks.withType(GenerateModuleMetadata).configureEach { + enabled = true +} + +tasks.register('configureCatalog') { + doConfigureCatalog() +} + +tasks.named('generateCatalogAsToml') { + dependsOn('configureCatalog') +} + +def doConfigureCatalog() { + for (proj in rootProject.allprojects) { + if (proj == project) { + continue + } + + String catalogName = proj.name + if (catalogName == 'fabric-api-base') { + catalogName = 'base' + } else if (catalogName == 'fabric-api-bom') { + catalogName = 'bom' + } else if (catalogName == 'deprecated') { + catalogName = 'deprecated-fabric-api' + } else if (catalogName == 'fabric-api') { + catalogName = 'fabric-api' + } else { + catalogName = catalogName.substring('fabric-'.length()) + } + + if (proj.parent != null && proj.parent.name == 'deprecated') { + catalogName = 'deprecated-' + catalogName + } + + catalog { + versionCatalog { + library(catalogName, "net.fabricmc.fabric-api:${proj.name}:${proj.version}") + } + } + } +} diff --git a/buildSrc/src/main/groovy/fabric-api.versioning.gradle b/buildSrc/src/main/groovy/fabric-api.versioning.gradle new file mode 100644 index 00000000000..543b762f739 --- /dev/null +++ b/buildSrc/src/main/groovy/fabric-api.versioning.gradle @@ -0,0 +1,10 @@ +import net.fabricmc.fabric.build.BumpVersionTask +import net.fabricmc.fabric.build.FabricApiBuildUtils + +if (project == rootProject) { + version = FabricApiBuildUtils.rootVersion(project) + logger.lifecycle("Building Fabric: " + version) + tasks.register('bumpVersions', BumpVersionTask) +} else { + version = FabricApiBuildUtils.moduleVersion(project) +} diff --git a/gradle/module-versioning.gradle b/buildSrc/src/main/groovy/net/fabricmc/fabric/build/BumpVersionTask.groovy similarity index 67% rename from gradle/module-versioning.gradle rename to buildSrc/src/main/groovy/net/fabricmc/fabric/build/BumpVersionTask.groovy index ed88948bba8..eb49c1c9b7a 100644 --- a/gradle/module-versioning.gradle +++ b/buildSrc/src/main/groovy/net/fabricmc/fabric/build/BumpVersionTask.groovy @@ -1,36 +1,30 @@ +package net.fabricmc.fabric.build -/** - * This task should be used to easily bump the major/minor/patch version of a fabric-api module. - * It will automatically bump the versions of dependent modules. - */ -tasks.register('bumpVersions', BumpVersionTask) +import org.gradle.api.DefaultTask +import org.gradle.api.tasks.TaskAction -class BumpVersionTask extends DefaultTask { +abstract class BumpVersionTask extends DefaultTask { BumpVersionTask() { group = "publishing" - outputs.upToDateWhen { false } } @TaskAction void runTask() { def scanner = new Scanner(System.in) - def toUpdate = [:] while (true) { println "Enter module name to update, or done to continue" - def input = scanner.nextLine() if (input == "done") { break } - // Bump all versions. To be used when buildscript changes are made. if (input == "allPatch") { project.getChildProjects().values().forEach { - if (it.name == "deprecated" || it.name == "fabric-api-bom" || it.name == "fabric-api-catalog") { + if (!FabricApiBuildUtils.isFabricModule(it)) { return } @@ -70,18 +64,15 @@ class BumpVersionTask extends DefaultTask { toUpdate.keySet().forEach { p -> project.allprojects.each { cp -> - if (cp.name == "deprecated" || cp.name == "fabric-api" || cp.name == "fabric-api-bom" || cp.name == "fabric-api-catalog") { + if (!FabricApiBuildUtils.isFabricModule(cp) || cp == project) { return } - def config = cp.configurations.api - config.allDependencies.forEach { dep -> - if (dep.name == p.name) { - if (!toUpdate.containsKey(cp)) { - println "Bumping patch of ${cp.name} as it depends on ${p.name}" - - temp.put(cp, 2) // Bump patch - } + def config = cp.configurations.findByName("api") + config?.allDependencies?.forEach { dep -> + if (dep.name == p.name && !toUpdate.containsKey(cp)) { + println "Bumping patch of ${cp.name} as it depends on ${p.name}" + temp.put(cp, 2) } } } @@ -107,7 +98,7 @@ class BumpVersionTask extends DefaultTask { def split = version.split("\\.") split[i] = (split[i] as Integer) + 1 - for (j in (i + 1) ..< split.length) { + for (j in (i + 1).. META_PROJECTS = [ + 'deprecated', + 'fabric-api-bom', + 'fabric-api-catalog' + ] as Set + + static final List DEBUG_ARGS = [ + "-enableassertions", + "-Dmixin.debug.verify=true", + "-Dmixin.debug.countInjections=true", + "-XX:+UseZGC", + "-XX:+UseCompactObjectHeaders", + "-XX:+AlwaysPreTouch", + "-XX:+UseStringDeduplication" + ].asImmutable() + + static final List DEV_ONLY_MODULES = [ + "fabric-client-gametest-api-v1", + "fabric-gametest-api-v1" + ].asImmutable() + + private FabricApiBuildUtils() { + } + + static boolean isMetaProject(Project project) { + return META_PROJECTS.contains(project.name) + } + + static boolean isFabricModule(Project project) { + return !isMetaProject(project) + } + + static String moduleName(String notation) { + return notation.startsWith(":") ? notation.substring(1) : notation + } + + static String projectPath(String notation) { + return notation.startsWith(":") ? notation : ":${notation}" + } + + static String rootVersion(Project project) { + def branchProvider = project.providers.of(GitBranchValueSource.class) {} + def suffix = project.providers.environmentVariable("CI").present + ? branchProvider.get().replace("/", "_") + : "local" + return "${project.findProperty('version')}+${suffix}" + } + + static String moduleVersion(Project project) { + def version = project.findProperty("${project.name}-version") + + if (!version) { + throw new NullPointerException("Could not find version for " + project.name) + } + + if (!project.providers.environmentVariable("CI").present) { + return version + "+local" + } + + def hashProvider = project.providers.of(CommitHashValueSource.class) { + parameters.directory = project.name + } + + return version + "+" + hashProvider.get().substring(0, 8) + sha256Hex(project.rootProject.minecraft_version).substring(0, 2) + } + + static void setupRepositories(Project project, RepositoryHandler repositories) { + if (project.providers.environmentVariable("MAVEN_URL").present) { + repositories.maven { + url = project.providers.environmentVariable("MAVEN_URL") + credentials { + username = project.providers.environmentVariable("MAVEN_USERNAME").get() + password = project.providers.environmentVariable("MAVEN_PASSWORD").get() + } + } + } + } + + static boolean publishedArtifactExists(Project project, String projectName, String projectVersion) { + if (!project.providers.environmentVariable("MAVEN_URL").present) { + return false + } + + def artifactPath = "https://maven.fabricmc.net/net/fabricmc/fabric-api/${projectName}/${projectVersion}/${projectName}-${projectVersion}.pom" + + return HttpClient.newHttpClient().withCloseable { client -> + def request = HttpRequest.newBuilder() + .uri(URI.create(artifactPath)) + .method("HEAD", HttpRequest.BodyPublishers.noBody()) + .build() + + def response = client.send(request, HttpResponse.BodyHandlers.discarding()) + response.statusCode() == 200 + } + } + + static void addPomMetadataInformation(Project project, MavenPom pom) { + def modJsonFile = project.file("src/main/resources/fabric.mod.json") + + if (!modJsonFile.exists()) { + modJsonFile = project.file("src/client/resources/fabric.mod.json") + } + + def modJson = new JsonSlurper().parse(modJsonFile) + pom.name = modJson.name + pom.url = "https://github.com/FabricMC/fabric/tree/HEAD/${project.rootDir.relativePath(project.projectDir)}" + pom.description = modJson.description + pom.licenses { + license { + name = "Apache-2.0" + url = "https://github.com/FabricMC/fabric/blob/HEAD/LICENSE" + } + } + pom.developers { + developer { + name = "FabricMC" + url = "https://fabricmc.net/" + } + } + pom.scm { + connection = "scm:git:https://github.com/FabricMC/fabric.git" + url = "https://github.com/FabricMC/fabric" + developerConnection = "scm:git:git@github.com:FabricMC/fabric.git" + } + pom.issueManagement { + system = "GitHub" + url = "https://github.com/FabricMC/fabric/issues" + } + } + + static void appendPomDependencies(Node pomNode, List> dependencies) { + def depsNode = pomNode.appendNode("dependencies") + + for (def dep in dependencies) { + def depNode = depsNode.appendNode("dependency") + + for (def entry in dep) { + depNode.appendNode(entry.key, entry.value) + } + } + } + + private static String sha256Hex(String input) { + def digest = MessageDigest.getInstance("SHA-256").digest(input.getBytes("UTF-8")) + return digest.collect { String.format("%02x", it) }.join() + } +} diff --git a/buildSrc/src/main/groovy/net/fabricmc/fabric/build/FabricApiModuleExtension.groovy b/buildSrc/src/main/groovy/net/fabricmc/fabric/build/FabricApiModuleExtension.groovy new file mode 100644 index 00000000000..03cf733dcef --- /dev/null +++ b/buildSrc/src/main/groovy/net/fabricmc/fabric/build/FabricApiModuleExtension.groovy @@ -0,0 +1,97 @@ +package net.fabricmc.fabric.build + +import org.gradle.api.Project +import org.gradle.api.publish.maven.MavenPublication + +class FabricApiModuleExtension { + final Project project + + FabricApiModuleExtension(Project project) { + this.project = project + } + + void moduleDependencies(List depNames) { + def deps = depNames.collect { project.dependencies.project(path: FabricApiBuildUtils.projectPath(it)) } + def depProjects = depNames.collect { project.rootProject.findProject(FabricApiBuildUtils.projectPath(it)) } + def clientOutputs = depProjects.collect { it.sourceSets.client.output } + + deps.each { + project.dependencies.add("api", it) + } + + clientOutputs.each { + project.dependencies.add("clientImplementation", it) + project.sourceSets.client.compileClasspath += it + project.sourceSets.client.runtimeClasspath += it + } + + project.tasks.named("compileClientJava").configure { + depProjects.each { dependsOn it.tasks.named("clientClasses") } + } + project.afterEvaluate { + project.tasks.named("compileClientJava").configure { + doFirst { + setClasspath(getClasspath().plus(project.files(depProjects.collect { + it.layout.buildDirectory.dir("classes/java/client") + }))) + } + } + project.tasks.named("compileTestmodClientJava").configure { + doFirst { + setClasspath(getClasspath().plus(project.files(depProjects.collect { + it.layout.buildDirectory.dir("classes/java/client") + }))) + } + } + } + + def depNodes = depNames.collect { + def depProject = project.rootProject.findProject(FabricApiBuildUtils.projectPath(it)) + [ + groupId: depProject.group, + artifactId: depProject.name, + version: FabricApiBuildUtils.moduleVersion(depProject), + scope: "compile" + ] + } + + project.publishing { + publications { + mavenJava(MavenPublication) { + pom.withXml { + FabricApiBuildUtils.appendPomDependencies(asNode(), depNodes) + } + } + } + } + } + + void testDependencies(List depNames) { + def deps = depNames.collect { project.dependencies.project(path: FabricApiBuildUtils.projectPath(it)) } + def depProjects = depNames.collect { project.rootProject.findProject(FabricApiBuildUtils.projectPath(it)) } + def clientOutputs = depProjects.collect { it.sourceSets.client.output } + + deps.each { + project.dependencies.add("testmodImplementation", it) + } + + clientOutputs.each { + project.dependencies.add("testmodClientImplementation", it) + project.sourceSets.testmodClient.compileClasspath += it + project.sourceSets.testmodClient.runtimeClasspath += it + } + + project.tasks.named("compileTestmodClientJava").configure { + depProjects.each { dependsOn it.tasks.named("clientClasses") } + } + project.afterEvaluate { + project.tasks.named("compileTestmodClientJava").configure { + doFirst { + setClasspath(getClasspath().plus(project.files(depProjects.collect { + it.layout.buildDirectory.dir("classes/java/client") + }))) + } + } + } + } +} diff --git a/gradle/package-info.gradle b/buildSrc/src/main/groovy/net/fabricmc/fabric/build/GeneratePackageInfosTask.groovy similarity index 54% rename from gradle/package-info.gradle rename to buildSrc/src/main/groovy/net/fabricmc/fabric/build/GeneratePackageInfosTask.groovy index 87192cfe571..6bec5028f3b 100644 --- a/gradle/package-info.gradle +++ b/buildSrc/src/main/groovy/net/fabricmc/fabric/build/GeneratePackageInfosTask.groovy @@ -1,33 +1,17 @@ -import java.nio.file.Files - -for (def sourceSet in [ - sourceSets.main, - sourceSets.client - ]) { - // We have to capture the source set name for the lazy string literals, - // otherwise it'll just be whatever the last source set is in the list. - def sourceSetName = sourceSet.name - def taskName = sourceSet.getTaskName('generate', 'PackageInfos') - def task = tasks.register(taskName, GeneratePackageInfos) { - group = 'fabric' - description = "Generates package-info files for $sourceSetName packages." - - // Only apply to default source directory since we also add the generated - // sources to the source set. - sourceRoot = file("src/$sourceSetName/java") - header = rootProject.file('HEADER') - outputDir = file("src/generated/$sourceSetName") - } - sourceSet.java.srcDir task +package net.fabricmc.fabric.build - def cleanTask = tasks.register(sourceSet.getTaskName('clean', 'PackageInfos'), Delete) { - group = 'fabric' - delete file("src/generated/$sourceSetName") - } - clean.dependsOn cleanTask -} - -abstract class GeneratePackageInfos extends DefaultTask { +import java.nio.file.Files +import org.gradle.api.DefaultTask +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputDirectory +import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.SkipWhenEmpty +import org.gradle.api.tasks.TaskAction + +abstract class GeneratePackageInfosTask extends DefaultTask { @InputFile File header @@ -41,27 +25,26 @@ abstract class GeneratePackageInfos extends DefaultTask { @OutputDirectory final DirectoryProperty outputDir = project.objects.directoryProperty() - GeneratePackageInfos() { + GeneratePackageInfosTask() { projectName.set(project.name) } @TaskAction - def run() { + void run() { def output = outputDir.get().asFile.toPath() output.deleteDir() - def headerText = header.readLines().join("\n") // normalize line endings + def headerText = header.readLines().join("\n") def root = sourceRoot.get().asFile.toPath() root.eachDirRecurse { - def containsJava = Files.list(it).any { - Files.isRegularFile(it) && it.fileName.toString().endsWith('.java') + def containsJava = Files.list(it).withCloseable { stream -> + stream.anyMatch { path -> Files.isRegularFile(path) && path.fileName.toString().endsWith('.java') } } if (!containsJava) { return } - // Check existing package-info.java to ensure it has @NullMarked def existingPackageInfo = it.resolve('package-info.java') if (Files.exists(existingPackageInfo)) { if (!existingPackageInfo.text.contains("@NullMarked")) { @@ -78,12 +61,10 @@ abstract class GeneratePackageInfos extends DefaultTask { def packageName = relativePath.toString().replace(File.separator, '.') if (packageName == "net.fabricmc.fabric.api.util" && projectName.get() == "fabric-content-registries-v0") { - // Hack: This package clashes with api-base, don't generate any annotations for it. return } - def implPattern = /^(net[\/\\]fabricmc[\/\\]fabric[\/\\](impl|mixin))/ - def isImpl = relativePath.toString() =~ implPattern + def isImpl = relativePath.toString() =~ /^(net[\/\\]fabricmc[\/\\]fabric[\/\\](impl|mixin))/ target.resolve('package-info.java').withWriter { if (isImpl) { diff --git a/buildSrc/src/main/groovy/net/fabricmc/fabric/build/ValidateAnnotationsTask.groovy b/buildSrc/src/main/groovy/net/fabricmc/fabric/build/ValidateAnnotationsTask.groovy new file mode 100644 index 00000000000..a330761c1ef --- /dev/null +++ b/buildSrc/src/main/groovy/net/fabricmc/fabric/build/ValidateAnnotationsTask.groovy @@ -0,0 +1,30 @@ +package net.fabricmc.fabric.build + +import org.gradle.api.tasks.SourceTask +import org.gradle.api.tasks.TaskAction + +abstract class ValidateAnnotationsTask extends SourceTask { + private static final def API_STATUS_INTERNAL = ~/@ApiStatus\.Internal/ + private static final def ENVIRONMENT = ~/@Environment/ + + @TaskAction + void run() { + for (def dir in ['api', 'impl', 'mixin', 'test']) { + getSource().matching { include "net/fabricmc/fabric/$dir/" }.forEach { + if (it.isDirectory()) { + return + } + + def contents = it.text + + if (ENVIRONMENT.matcher(contents).find()) { + throw new RuntimeException("Found @Environment annotation in file: $it") + } + + if (dir != "api" && API_STATUS_INTERNAL.matcher(contents).find()) { + throw new RuntimeException("Found @ApiStatus.Internal in implementation file: " + it) + } + } + } + } +} diff --git a/gradle/module-validation.gradle b/buildSrc/src/main/groovy/net/fabricmc/fabric/build/ValidateModuleTask.groovy similarity index 65% rename from gradle/module-validation.gradle rename to buildSrc/src/main/groovy/net/fabricmc/fabric/build/ValidateModuleTask.groovy index ae3fef8ce1b..36bc2af720d 100644 --- a/gradle/module-validation.gradle +++ b/buildSrc/src/main/groovy/net/fabricmc/fabric/build/ValidateModuleTask.groovy @@ -1,32 +1,14 @@ -import groovy.json.JsonSlurper - -/* - * This buildscript contains tasks related to the validation of each module in fabric api. - * - * Right now this task verifies each Fabric API module has a module lifecycle specified. - * More functionality will probably be added in the future. - */ +package net.fabricmc.fabric.build -subprojects { - if (it.name == "deprecated" || it.name == "fabric-api-bom" || it.name == "fabric-api-catalog") { - return - } - - // Create the task - def validateModules = tasks.register("validateModules", ValidateModuleTask) - tasks.check.dependsOn(validateModules) -} +import groovy.json.JsonSlurper +import org.gradle.api.DefaultTask +import org.gradle.api.GradleException +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.TaskAction -/** - * Verifies that each module has the required custom values for module lifecycle in it's FMJ. - * - *

Example: - *

{@code
- * "custom": {
- *   "fabric-api:module-lifecycle": "stable"
- * }
- * }
- */ abstract class ValidateModuleTask extends DefaultTask { @InputFile abstract RegularFileProperty getFmj() @@ -42,8 +24,6 @@ abstract class ValidateModuleTask extends DefaultTask { ValidateModuleTask() { group = "verification" - - // No outputs outputs.upToDateWhen { true } def file = project.file("src/main/resources/fabric.mod.json") @@ -53,7 +33,6 @@ abstract class ValidateModuleTask extends DefaultTask { } fmj.set(file) - projectName.set(project.name) projectPath.set(project.path) loaderVersion.set(project.loader_version) @@ -61,9 +40,7 @@ abstract class ValidateModuleTask extends DefaultTask { @TaskAction void validate() { - def file = fmj.get().asFile - - def json = new JsonSlurper().parse(file) + def json = new JsonSlurper().parse(fmj.get().asFile) if (json.custom == null) { throw new GradleException("Module ${projectName.get()} does not have a custom value containing module lifecycle!") @@ -75,11 +52,10 @@ abstract class ValidateModuleTask extends DefaultTask { throw new GradleException("Module ${projectName.get()} does not have module lifecycle in custom values!") } - if (!moduleLifecycle instanceof String) { + if (!(moduleLifecycle instanceof String)) { throw new GradleException("Module ${projectName.get()} has an invalid module lifecycle value. The value must be a string but read a ${moduleLifecycle.class}") } - // Validate the lifecycle value switch (moduleLifecycle) { case "stable": case "experimental": @@ -90,7 +66,7 @@ abstract class ValidateModuleTask extends DefaultTask { } break default: - throw new GradleException("Module ${projectName.get()} has an invalid module lifecycle ${json.custom.get('fabric-api:module-lifecycle')}") + throw new GradleException("Module ${projectName.get()} has an invalid module lifecycle ${moduleLifecycle}") } if (json.depends == null) { @@ -98,7 +74,7 @@ abstract class ValidateModuleTask extends DefaultTask { } if (json.depends.fabricloader != ">=${loaderVersion.get()}") { - throw new GradleException("Module ${projectName.get()} does not have a valid fabricloader value! Got \"${json.depends.fabricloader}\" but expected \">=${project.loader_version}\"") + throw new GradleException("Module ${projectName.get()} does not have a valid fabricloader value! Got \"${json.depends.fabricloader}\" but expected \">=${loaderVersion.get()}\"") } } } diff --git a/deprecated/build.gradle b/deprecated/build.gradle index 5dbef4654d7..e53f3e6e28a 100644 --- a/deprecated/build.gradle +++ b/deprecated/build.gradle @@ -1,46 +1,3 @@ -/** - * This project generates a maven bill of materials (BOM) that includes the deprecated modules, alongside the main project. - */ -version = rootProject.version - -publishing { - publications { - mavenJava(MavenPublication) { - artifactId = 'fabric-api-deprecated' - - List> dependencies = [] - - allprojects.each { - if (it.name == "deprecated") { - return // Dont depend on yourself :) - } - - // Depend on all of the deprecated projects - if (!it.path.startsWith(":deprecated")) { - return - } - - dependencies.add([ - 'groupId': it.group, - 'artifactId': it.name, - 'version': getSubprojectVersion(it), - 'scope': 'compile' - ]) - } - - def thisGroup = group - def thisVersion = version - - pom.withXml { - def depsNode = asNode().appendNode("dependencies") - for (dep in dependencies) { - def depNode = depsNode.appendNode("dependency") - depNode.appendNode("groupId", dep['groupId']) - depNode.appendNode("artifactId", dep['artifactId']) - depNode.appendNode("version", dep['version']) - depNode.appendNode("scope", dep['scope']) - } - } - } - } +plugins { + id 'fabric-api.deprecated-bom' } diff --git a/deprecated/fabric-resource-loader-v0/build.gradle b/deprecated/fabric-resource-loader-v0/build.gradle index 762ea15d120..ed0d91c0454 100644 --- a/deprecated/fabric-resource-loader-v0/build.gradle +++ b/deprecated/fabric-resource-loader-v0/build.gradle @@ -1,8 +1,10 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} -moduleDependencies(project, ['fabric-api-base', 'fabric-resource-loader-v1']) +fabricApiModule.moduleDependencies(['fabric-api-base', 'fabric-resource-loader-v1']) -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-lifecycle-events-v1', ':fabric-api-base', ':fabric-gametest-api-v1', diff --git a/fabric-api-base/build.gradle b/fabric-api-base/build.gradle index fc1eb105c53..6774e35e997 100644 --- a/fabric-api-base/build.gradle +++ b/fabric-api-base/build.gradle @@ -1,6 +1,8 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-command-api-v2', ':fabric-lifecycle-events-v1', ':fabric-screen-api-v1' diff --git a/fabric-api-bom/build.gradle b/fabric-api-bom/build.gradle index 2a48fd7f8d4..97cf0776011 100644 --- a/fabric-api-bom/build.gradle +++ b/fabric-api-bom/build.gradle @@ -1,31 +1,3 @@ plugins { - id 'java-platform' -} - -version = rootProject.version - -publishing.publications { - register('mavenJava', MavenPublication) { - from(components['javaPlatform']) - } -} - -tasks.withType(GenerateModuleMetadata) { - // todo: RemoteSignJar fails when this is false (as set by parent build script) - enabled = true -} - -dependencies { - constraints { - for (proj in rootProject.allprojects) { - if (proj == project) { // the bom itself - continue - } - if (proj.name == 'fabric-api-catalog') { - continue - } - - api(project(proj.path)) - } - } + id 'fabric-api.maven-bom' } diff --git a/fabric-api-catalog/build.gradle b/fabric-api-catalog/build.gradle index 18f4ce38882..a8a018adf72 100644 --- a/fabric-api-catalog/build.gradle +++ b/fabric-api-catalog/build.gradle @@ -1,56 +1,3 @@ plugins { - id 'version-catalog' -} - -version = rootProject.version - -publishing.publications { - register('mavenJava', MavenPublication) { - from components.versionCatalog - } -} - -tasks.withType(GenerateModuleMetadata) { - // todo: RemoteSignJar fails when this is false (as set by parent build script) - enabled = true -} - -// Avoid configuration ordering issues by creating the catalog entries during task execution time -tasks.register('configureCatalog') { - doConfigureCatalog() -} - -tasks.named('generateCatalogAsToml') { - dependsOn('configureCatalog') -} - -def doConfigureCatalog() { - for (proj in rootProject.allprojects) { - if (proj == project) { // the catalog itself - continue - } - - String catalogName = proj.name - if (catalogName == 'fabric-api-base') { - catalogName = 'base' - } else if (catalogName == 'fabric-api-bom') { - catalogName = 'bom' - } else if (catalogName == 'deprecated') { - catalogName = 'deprecated-fabric-api' - } else if (catalogName == 'fabric-api') { - catalogName = 'fabric-api' - } else { - catalogName = catalogName.substring('fabric-'.length()) - } - - if (proj.parent != null && proj.parent.name == 'deprecated') { - catalogName = 'deprecated-' + catalogName - } - - catalog { - versionCatalog { - library(catalogName, "net.fabricmc.fabric-api:${proj.name}:${proj.version}") - } - } - } + id 'fabric-api.version-catalog' } diff --git a/fabric-api-lookup-api-v1/build.gradle b/fabric-api-lookup-api-v1/build.gradle index 860d2b0801a..c8e44af3398 100644 --- a/fabric-api-lookup-api-v1/build.gradle +++ b/fabric-api-lookup-api-v1/build.gradle @@ -1,11 +1,13 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} -moduleDependencies(project, [ +fabricApiModule.moduleDependencies([ 'fabric-api-base', 'fabric-lifecycle-events-v1' ]) -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-rendering-v1', ':fabric-object-builder-api-v1', ':fabric-transitive-access-wideners-v1' diff --git a/fabric-biome-api-v1/build.gradle b/fabric-biome-api-v1/build.gradle index a5903807f4f..dd7c3043aa0 100644 --- a/fabric-biome-api-v1/build.gradle +++ b/fabric-biome-api-v1/build.gradle @@ -1,10 +1,12 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file("src/main/resources/fabric-biome-api-v1.classtweaker") } -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-api-base', ':fabric-resource-loader-v1', ':fabric-registry-sync-v0', diff --git a/fabric-block-api-v1/build.gradle b/fabric-block-api-v1/build.gradle index 1912cf8d419..599ea9c0309 100644 --- a/fabric-block-api-v1/build.gradle +++ b/fabric-block-api-v1/build.gradle @@ -1,9 +1,11 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file('src/main/resources/fabric-block-api-v1.classtweaker') } -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-rendering-v1', ]) diff --git a/fabric-block-getter-api-v2/build.gradle b/fabric-block-getter-api-v2/build.gradle index 79e8927a39a..491895f0e10 100644 --- a/fabric-block-getter-api-v2/build.gradle +++ b/fabric-block-getter-api-v2/build.gradle @@ -1,4 +1,6 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file('src/main/resources/fabric-block-getter-api-v2.classtweaker') diff --git a/fabric-client-gametest-api-v1/build.gradle b/fabric-client-gametest-api-v1/build.gradle index da0c75e18ab..bc70cd3dec9 100644 --- a/fabric-client-gametest-api-v1/build.gradle +++ b/fabric-client-gametest-api-v1/build.gradle @@ -1,4 +1,6 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file('src/client/resources/fabric-client-gametest-api-v1.classtweaker') diff --git a/fabric-command-api-v2/build.gradle b/fabric-command-api-v2/build.gradle index 2c057b35e78..3453a53b29d 100644 --- a/fabric-command-api-v2/build.gradle +++ b/fabric-command-api-v2/build.gradle @@ -1,8 +1,10 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} -moduleDependencies(project, ['fabric-api-base']) +fabricApiModule.moduleDependencies(['fabric-api-base']) -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-lifecycle-events-v1', ]) diff --git a/fabric-content-registries-v0/build.gradle b/fabric-content-registries-v0/build.gradle index 29381d306e9..c1ad1045ea5 100644 --- a/fabric-content-registries-v0/build.gradle +++ b/fabric-content-registries-v0/build.gradle @@ -1,10 +1,12 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file("src/main/resources/fabric-content-registries-v0.classtweaker") } -moduleDependencies(project, [ +fabricApiModule.moduleDependencies([ 'fabric-api-base', 'fabric-lifecycle-events-v1', 'fabric-resource-loader-v1' diff --git a/fabric-convention-tags-v2/build.gradle b/fabric-convention-tags-v2/build.gradle index 131ee71c836..a18af841b27 100644 --- a/fabric-convention-tags-v2/build.gradle +++ b/fabric-convention-tags-v2/build.gradle @@ -1,15 +1,17 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file('src/main/resources/fabric-convention-tags-v2.classtweaker') } -moduleDependencies(project, [ +fabricApiModule.moduleDependencies([ 'fabric-api-base', 'fabric-lifecycle-events-v1' ]) -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-lifecycle-events-v1', ]) diff --git a/fabric-crash-report-info-v1/build.gradle b/fabric-crash-report-info-v1/build.gradle index 64f55fd09ee..4d72ffd3f06 100644 --- a/fabric-crash-report-info-v1/build.gradle +++ b/fabric-crash-report-info-v1/build.gradle @@ -1,5 +1,7 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-command-api-v2' ]) diff --git a/fabric-creative-tab-api-v1/build.gradle b/fabric-creative-tab-api-v1/build.gradle index b414c7cc588..3560d5d9215 100644 --- a/fabric-creative-tab-api-v1/build.gradle +++ b/fabric-creative-tab-api-v1/build.gradle @@ -1,6 +1,8 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} -moduleDependencies(project, [ +fabricApiModule.moduleDependencies([ 'fabric-api-base', 'fabric-resource-loader-v1' ]) diff --git a/fabric-data-attachment-api-v1/build.gradle b/fabric-data-attachment-api-v1/build.gradle index 1cf1afa68e4..1456144a71d 100644 --- a/fabric-data-attachment-api-v1/build.gradle +++ b/fabric-data-attachment-api-v1/build.gradle @@ -1,17 +1,19 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file('src/main/resources/fabric-data-attachment-api-v1.classtweaker') } -moduleDependencies(project, [ +fabricApiModule.moduleDependencies([ 'fabric-api-base', ':fabric-entity-events-v1', ':fabric-object-builder-api-v1', ':fabric-networking-api-v1' ]) -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-lifecycle-events-v1', ':fabric-biome-api-v1', ':fabric-command-api-v2', diff --git a/fabric-data-generation-api-v1/build.gradle b/fabric-data-generation-api-v1/build.gradle index 8e37efb8f17..0a3ba4ae711 100644 --- a/fabric-data-generation-api-v1/build.gradle +++ b/fabric-data-generation-api-v1/build.gradle @@ -1,6 +1,8 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} -moduleDependencies(project, [ +fabricApiModule.moduleDependencies([ 'fabric-convention-tags-v2', 'fabric-recipe-api-v1', 'fabric-registry-sync-v0', @@ -8,7 +10,7 @@ moduleDependencies(project, [ 'fabric-tag-api-v1', ]) -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-creative-tab-api-v1', ':fabric-object-builder-api-v1' ]) diff --git a/fabric-debug-api-v1/build.gradle b/fabric-debug-api-v1/build.gradle index 91ac94ae90f..de944a6384e 100644 --- a/fabric-debug-api-v1/build.gradle +++ b/fabric-debug-api-v1/build.gradle @@ -1,10 +1,12 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} -moduleDependencies(project, [ +fabricApiModule.moduleDependencies([ 'fabric-api-base' ]) -testDependencies(project, [ +fabricApiModule.testDependencies([ ]) loom { diff --git a/fabric-dimensions-v1/build.gradle b/fabric-dimensions-v1/build.gradle index 8bfe314df96..47adaa47462 100644 --- a/fabric-dimensions-v1/build.gradle +++ b/fabric-dimensions-v1/build.gradle @@ -1,11 +1,13 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} -moduleDependencies(project, [ +fabricApiModule.moduleDependencies([ 'fabric-api-base', 'fabric-lifecycle-events-v1' ]) -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-resource-loader-v1', ':fabric-client-gametest-api-v1' ]) diff --git a/fabric-entity-events-v1/build.gradle b/fabric-entity-events-v1/build.gradle index 54d84046d6c..5fce111f2bf 100644 --- a/fabric-entity-events-v1/build.gradle +++ b/fabric-entity-events-v1/build.gradle @@ -1,12 +1,14 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file('src/main/resources/fabric-entity-events-v1.classtweaker') } -moduleDependencies(project, ['fabric-api-base']) +fabricApiModule.moduleDependencies(['fabric-api-base']) -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-command-api-v2', ':fabric-networking-api-v1', ':fabric-registry-sync-v0', diff --git a/fabric-events-interaction-v0/build.gradle b/fabric-events-interaction-v0/build.gradle index 5ea804ac6f6..4ea272fffc1 100644 --- a/fabric-events-interaction-v0/build.gradle +++ b/fabric-events-interaction-v0/build.gradle @@ -1,7 +1,9 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} -moduleDependencies(project, ['fabric-api-base', 'fabric-networking-api-v1']) +fabricApiModule.moduleDependencies(['fabric-api-base', 'fabric-networking-api-v1']) -testDependencies(project, [ +fabricApiModule.testDependencies([ 'fabric-client-gametest-api-v1' ]) diff --git a/fabric-game-rule-api-v1/build.gradle b/fabric-game-rule-api-v1/build.gradle index a6858660bd9..6733ed43473 100644 --- a/fabric-game-rule-api-v1/build.gradle +++ b/fabric-game-rule-api-v1/build.gradle @@ -1,12 +1,14 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file("src/main/resources/fabric-game-rule-api-v1.classtweaker") } -moduleDependencies(project, ['fabric-api-base']) +fabricApiModule.moduleDependencies(['fabric-api-base']) -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-api-base', ':fabric-lifecycle-events-v1', ':fabric-resource-loader-v1' diff --git a/fabric-gametest-api-v1/build.gradle b/fabric-gametest-api-v1/build.gradle index 08e8c3d9fa5..4360925efbf 100644 --- a/fabric-gametest-api-v1/build.gradle +++ b/fabric-gametest-api-v1/build.gradle @@ -1,4 +1,6 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file("src/main/resources/fabric-gametest-api-v1.classtweaker") @@ -15,7 +17,7 @@ loom { } } -moduleDependencies(project, [ +fabricApiModule.moduleDependencies([ 'fabric-api-base', 'fabric-registry-sync-v0', 'fabric-resource-loader-v1', diff --git a/fabric-item-api-v1/build.gradle b/fabric-item-api-v1/build.gradle index 6ab22b6e207..153c031f4e1 100644 --- a/fabric-item-api-v1/build.gradle +++ b/fabric-item-api-v1/build.gradle @@ -1,11 +1,13 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file("src/main/resources/fabric-item-api-v1.classtweaker") } -moduleDependencies(project, ['fabric-api-base', 'fabric-resource-loader-v1']) +fabricApiModule.moduleDependencies(['fabric-api-base', 'fabric-resource-loader-v1']) -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-content-registries-v0', ]) diff --git a/fabric-key-mapping-api-v1/build.gradle b/fabric-key-mapping-api-v1/build.gradle index 68b99e5db0f..be3dcaba85c 100644 --- a/fabric-key-mapping-api-v1/build.gradle +++ b/fabric-key-mapping-api-v1/build.gradle @@ -1,6 +1,8 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-api-base', ':fabric-lifecycle-events-v1', ':fabric-resource-loader-v1' diff --git a/fabric-lifecycle-events-v1/build.gradle b/fabric-lifecycle-events-v1/build.gradle index 7178d1ef763..810b28943cb 100644 --- a/fabric-lifecycle-events-v1/build.gradle +++ b/fabric-lifecycle-events-v1/build.gradle @@ -1,7 +1,9 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file("src/main/resources/fabric-lifecycle-events-v1.classtweaker") } -moduleDependencies(project, ['fabric-api-base']) +fabricApiModule.moduleDependencies(['fabric-api-base']) diff --git a/fabric-loot-api-v3/build.gradle b/fabric-loot-api-v3/build.gradle index ccb92c75706..319831f153b 100644 --- a/fabric-loot-api-v3/build.gradle +++ b/fabric-loot-api-v3/build.gradle @@ -1,10 +1,12 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file('src/main/resources/fabric-loot-api-v3.classtweaker') } -moduleDependencies(project, [ +fabricApiModule.moduleDependencies([ 'fabric-api-base', 'fabric-resource-loader-v1' ]) diff --git a/fabric-menu-api-v1/build.gradle b/fabric-menu-api-v1/build.gradle index 7f20fc87538..60ab64e6984 100644 --- a/fabric-menu-api-v1/build.gradle +++ b/fabric-menu-api-v1/build.gradle @@ -1,16 +1,18 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file('src/main/resources/fabric-menu-api-v1.classtweaker') } -moduleDependencies(project, [ +fabricApiModule.moduleDependencies([ 'fabric-api-base', 'fabric-networking-api-v1', 'fabric-registry-sync-v0' ]) -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-object-builder-api-v1', ':fabric-resource-loader-v1', ':fabric-transitive-access-wideners-v1' diff --git a/fabric-message-api-v1/build.gradle b/fabric-message-api-v1/build.gradle index a733beb92bb..f8486b9faa4 100644 --- a/fabric-message-api-v1/build.gradle +++ b/fabric-message-api-v1/build.gradle @@ -1,5 +1,7 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} -moduleDependencies(project, ['fabric-api-base']) +fabricApiModule.moduleDependencies(['fabric-api-base']) -testDependencies(project, ['fabric-command-api-v2']) +fabricApiModule.testDependencies(['fabric-command-api-v2']) diff --git a/fabric-model-loading-api-v1/build.gradle b/fabric-model-loading-api-v1/build.gradle index 84af2960727..a9ae716c9e4 100644 --- a/fabric-model-loading-api-v1/build.gradle +++ b/fabric-model-loading-api-v1/build.gradle @@ -1,11 +1,13 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} -moduleDependencies(project, [ +fabricApiModule.moduleDependencies([ 'fabric-api-base', 'fabric-renderer-api-v1' ]) -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-renderer-api-v1', ':fabric-renderer-indigo', ':fabric-rendering-v1', diff --git a/fabric-networking-api-v1/build.gradle b/fabric-networking-api-v1/build.gradle index c9dbcbccf00..e611a82e200 100644 --- a/fabric-networking-api-v1/build.gradle +++ b/fabric-networking-api-v1/build.gradle @@ -1,8 +1,10 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} -moduleDependencies(project, ['fabric-api-base']) +fabricApiModule.moduleDependencies(['fabric-api-base']) -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-command-api-v2', ':fabric-lifecycle-events-v1', ':fabric-key-mapping-api-v1' diff --git a/fabric-object-builder-api-v1/build.gradle b/fabric-object-builder-api-v1/build.gradle index 8c4fde6e552..11640631631 100644 --- a/fabric-object-builder-api-v1/build.gradle +++ b/fabric-object-builder-api-v1/build.gradle @@ -1,12 +1,14 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} -moduleDependencies(project, [ +fabricApiModule.moduleDependencies([ 'fabric-api-base', 'fabric-registry-sync-v0', 'fabric-resource-loader-v1' ]) -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-command-api-v2', ':fabric-lifecycle-events-v1', ':fabric-rendering-v1' diff --git a/fabric-particles-v1/build.gradle b/fabric-particles-v1/build.gradle index 70fafde28bc..43c8a4d8a27 100644 --- a/fabric-particles-v1/build.gradle +++ b/fabric-particles-v1/build.gradle @@ -1,15 +1,17 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file("src/main/resources/fabric-particles-v1.classtweaker") } -moduleDependencies(project, [ +fabricApiModule.moduleDependencies([ 'fabric-api-base', 'fabric-networking-api-v1' ]) -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-command-api-v2', ':fabric-rendering-v1', ':fabric-resource-loader-v1' diff --git a/fabric-permission-api-v1/build.gradle b/fabric-permission-api-v1/build.gradle index b86e587dda3..16e37287f08 100644 --- a/fabric-permission-api-v1/build.gradle +++ b/fabric-permission-api-v1/build.gradle @@ -1,14 +1,16 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file('src/main/resources/fabric-permission-api-v1.classtweaker') } -moduleDependencies(project, [ +fabricApiModule.moduleDependencies([ ":fabric-api-base" ]) -testDependencies(project, [ +fabricApiModule.testDependencies([ ":fabric-command-api-v2", ":fabric-lifecycle-events-v1", ":fabric-networking-api-v1" diff --git a/fabric-recipe-api-v1/build.gradle b/fabric-recipe-api-v1/build.gradle index c00c3fd0a61..d0e3eba8221 100644 --- a/fabric-recipe-api-v1/build.gradle +++ b/fabric-recipe-api-v1/build.gradle @@ -1,15 +1,17 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file('src/main/resources/fabric-recipe-api-v1.classtweaker') } -moduleDependencies(project, [ +fabricApiModule.moduleDependencies([ ':fabric-lifecycle-events-v1', 'fabric-networking-api-v1', ]) -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-lifecycle-events-v1', ':fabric-registry-sync-v0', ]) diff --git a/fabric-registry-sync-v0/build.gradle b/fabric-registry-sync-v0/build.gradle index a1ee9ba16aa..97eaba607b8 100644 --- a/fabric-registry-sync-v0/build.gradle +++ b/fabric-registry-sync-v0/build.gradle @@ -1,15 +1,17 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file("src/main/resources/fabric-registry-sync-v0.classtweaker") } -moduleDependencies(project, [ +fabricApiModule.moduleDependencies([ 'fabric-api-base', 'fabric-networking-api-v1' ]) -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-lifecycle-events-v1', ':fabric-command-api-v2', ]) diff --git a/fabric-renderer-api-v1/build.gradle b/fabric-renderer-api-v1/build.gradle index d18e011e2b6..8d5be9e8ae2 100644 --- a/fabric-renderer-api-v1/build.gradle +++ b/fabric-renderer-api-v1/build.gradle @@ -1,12 +1,14 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} -moduleDependencies(project, [ +fabricApiModule.moduleDependencies([ ':fabric-api-base', ':fabric-rendering-v1', ':fabric-transitive-access-wideners-v1' ]) -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-block-api-v1', ':fabric-block-getter-api-v2', ':fabric-model-loading-api-v1', diff --git a/fabric-renderer-indigo/build.gradle b/fabric-renderer-indigo/build.gradle index 12885b51b09..00bc09bf25c 100644 --- a/fabric-renderer-indigo/build.gradle +++ b/fabric-renderer-indigo/build.gradle @@ -1,10 +1,12 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file("src/client/resources/fabric-renderer-indigo.classtweaker") } -moduleDependencies(project, [ +fabricApiModule.moduleDependencies([ 'fabric-api-base', 'fabric-renderer-api-v1', 'fabric-rendering-v1' diff --git a/fabric-rendering-fluids-v1/build.gradle b/fabric-rendering-fluids-v1/build.gradle index 409b49f2d14..d7ba5908548 100644 --- a/fabric-rendering-fluids-v1/build.gradle +++ b/fabric-rendering-fluids-v1/build.gradle @@ -1,7 +1,9 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file('src/main/resources/fabric-rendering-fluids-v1.classtweaker') } -moduleDependencies(project, ['fabric-api-base']) +fabricApiModule.moduleDependencies(['fabric-api-base']) diff --git a/fabric-rendering-v1/build.gradle b/fabric-rendering-v1/build.gradle index 03e7f6a0eec..f4e11434d41 100644 --- a/fabric-rendering-v1/build.gradle +++ b/fabric-rendering-v1/build.gradle @@ -1,16 +1,18 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file('src/client/resources/fabric-rendering-v1.classtweaker') } -moduleDependencies(project, [ +fabricApiModule.moduleDependencies([ ':fabric-api-base', ':fabric-transitive-access-wideners-v1', ':fabric-lifecycle-events-v1' ]) -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-client-gametest-api-v1', ':fabric-item-api-v1', ':fabric-object-builder-api-v1', diff --git a/fabric-resource-conditions-api-v1/build.gradle b/fabric-resource-conditions-api-v1/build.gradle index 84e239cecca..0c93379e7e2 100644 --- a/fabric-resource-conditions-api-v1/build.gradle +++ b/fabric-resource-conditions-api-v1/build.gradle @@ -1,10 +1,12 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file("src/main/resources/fabric-resource-conditions-api-v1.classtweaker") } -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-lifecycle-events-v1', ':fabric-resource-loader-v1' ]) diff --git a/fabric-resource-loader-v1/build.gradle b/fabric-resource-loader-v1/build.gradle index 591c6ea58d1..56dbb071f71 100644 --- a/fabric-resource-loader-v1/build.gradle +++ b/fabric-resource-loader-v1/build.gradle @@ -1,12 +1,14 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file("src/main/resources/fabric-resource-loader-v1.classtweaker") } -moduleDependencies(project, ['fabric-api-base']) +fabricApiModule.moduleDependencies(['fabric-api-base']) -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-lifecycle-events-v1', ':fabric-api-base', ':fabric-gametest-api-v1', diff --git a/fabric-screen-api-v1/build.gradle b/fabric-screen-api-v1/build.gradle index 9ced6ef8b49..4162d5d89af 100644 --- a/fabric-screen-api-v1/build.gradle +++ b/fabric-screen-api-v1/build.gradle @@ -1,3 +1,5 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} -moduleDependencies(project, ['fabric-api-base']) +fabricApiModule.moduleDependencies(['fabric-api-base']) diff --git a/fabric-serialization-api-v1/build.gradle b/fabric-serialization-api-v1/build.gradle index 714fb5d4d34..814f72ae199 100644 --- a/fabric-serialization-api-v1/build.gradle +++ b/fabric-serialization-api-v1/build.gradle @@ -1,4 +1,6 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file('src/main/resources/fabric-serialization-api-v1.classtweaker') diff --git a/fabric-sound-api-v1/build.gradle b/fabric-sound-api-v1/build.gradle index ad829bbf8a1..f9a8c81007d 100644 --- a/fabric-sound-api-v1/build.gradle +++ b/fabric-sound-api-v1/build.gradle @@ -1,10 +1,12 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file('src/client/resources/fabric-sound-api-v1.classtweaker') } -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-api-base', ':fabric-resource-loader-v1', ':fabric-command-api-v2' diff --git a/fabric-tag-api-v1/build.gradle b/fabric-tag-api-v1/build.gradle index ce5741d79ce..dea3ce7a460 100644 --- a/fabric-tag-api-v1/build.gradle +++ b/fabric-tag-api-v1/build.gradle @@ -1,15 +1,17 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file('src/main/resources/fabric-tag-api-v1.classtweaker') } -moduleDependencies(project, [ +fabricApiModule.moduleDependencies([ 'fabric-api-base', 'fabric-resource-loader-v1' ]) -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-convention-tags-v2', ':fabric-client-gametest-api-v1', ':fabric-lifecycle-events-v1', diff --git a/fabric-transfer-api-v1/build.gradle b/fabric-transfer-api-v1/build.gradle index 11be313e00b..30059d6e309 100644 --- a/fabric-transfer-api-v1/build.gradle +++ b/fabric-transfer-api-v1/build.gradle @@ -1,6 +1,8 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} -moduleDependencies(project, [ +fabricApiModule.moduleDependencies([ 'fabric-api-base', 'fabric-api-lookup-api-v1', 'fabric-lifecycle-events-v1', @@ -8,7 +10,7 @@ moduleDependencies(project, [ 'fabric-rendering-fluids-v1', ]) -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-object-builder-api-v1', ':fabric-rendering-v1', ':fabric-resource-loader-v1', diff --git a/fabric-transitive-access-wideners-v1/build.gradle b/fabric-transitive-access-wideners-v1/build.gradle index 76d5f1e57ba..a4043838aa3 100644 --- a/fabric-transitive-access-wideners-v1/build.gradle +++ b/fabric-transitive-access-wideners-v1/build.gradle @@ -1,10 +1,12 @@ -version = getSubprojectVersion(project) +plugins { + id 'fabric-api.module' +} loom { accessWidenerPath = file('src/main/resources/fabric-transitive-access-wideners-v1.classtweaker') } -testDependencies(project, [ +fabricApiModule.testDependencies([ ':fabric-rendering-v1', ':fabric-object-builder-api-v1' ]) diff --git a/gradle/validate-annotations.gradle b/gradle/validate-annotations.gradle deleted file mode 100644 index 4ab352a4018..00000000000 --- a/gradle/validate-annotations.gradle +++ /dev/null @@ -1,49 +0,0 @@ -tasks.register('validateAnnotations', ValidateAnnotations) { - group = 'fabric' - description = "Validate annotations used in Fabric API code." - - outputs.upToDateWhen { true } // Task has no outputs - - // Only apply to default source directories since there's also generated package-info files. - source file("src/client/java") - source file("src/main/java") - source file("src/testmod/java") - source file("src/testmodClient/java") -} - -tasks.check.dependsOn "validateAnnotations" - -abstract class ValidateAnnotations extends SourceTask { - private static final def API_STATUS_INTERNAL = ~/@ApiStatus\.Internal/ - private static final def ENVIRONMENT = ~/@Environment/ - - @TaskAction - def run() { - for (def dir in [ - 'api', - 'impl', - 'mixin', - 'test' - ]) { - getSource().matching { include "net/fabricmc/fabric/$dir/" }.forEach { - if (it.isDirectory()) { - return - } - - def contents = it.text - - // @Environment is never allowed - if (ENVIRONMENT.matcher(contents).find()) { - throw new RuntimeException("Found @Environment annotation in file: $it") - } - - // @ApiStatus.Internal is only allowed in api packages (it's auto-generated for impl and mixin packages) - if (dir != "api") { - if (API_STATUS_INTERNAL.matcher(contents).find()) { - throw new RuntimeException("Found @ApiStatus.Internal in implementation file: " + it) - } - } - } - } - } -} From bbadda58b4aa6a4de325bef094d0a69081e39fea Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Thu, 4 Jun 2026 21:33:44 +0100 Subject: [PATCH 02/23] Maybe fix client tests --- build.gradle | 1 - .../src/main/groovy/fabric-api.root.gradle | 37 +++++++++++++++---- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index c6fc6e5169f..b6dec108b16 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,4 @@ plugins { - id "eclipse" id "com.diffplug.spotless" version "8.5.1" apply false id "me.modmuss50.remotesign" version "0.5.0" apply false id "me.modmuss50.mod-publish-plugin" version "2.0.0-beta.1" apply false diff --git a/buildSrc/src/main/groovy/fabric-api.root.gradle b/buildSrc/src/main/groovy/fabric-api.root.gradle index 01dd5df4033..bd26f3287cd 100644 --- a/buildSrc/src/main/groovy/fabric-api.root.gradle +++ b/buildSrc/src/main/groovy/fabric-api.root.gradle @@ -211,15 +211,13 @@ tasks.publishMods.dependsOn checkVersion publish.mustRunAfter checkVersion gradle.projectsEvaluated { - for (def moduleProject : includedModuleProjects) { - loom.mods.register(moduleProject.name) { - sourceSet moduleProject.sourceSets.main - sourceSet moduleProject.sourceSets.client + loom.runs.configureEach { + if (it.name == "gametest" || it.name == "autoTestServer") { + it.source sourceSets.testmod } - loom.mods.register(moduleProject.name + "-testmod") { - sourceSet moduleProject.sourceSets.testmod - sourceSet moduleProject.sourceSets.testmodClient + if (it.name == "clientGametest") { + it.source sourceSets.testmodClient } } @@ -231,6 +229,31 @@ gradle.projectsEvaluated { nestedTestModJars.from(moduleProject.tasks.named("testmodJar")) } + + tasks.named("runGametest") { + classpath(nestedTestModJars) + } + + tasks.named("runAutoTestServer") { + classpath(nestedTestModJars) + } + + tasks.named("runClientGametest") { + classpath(nestedTestModJars) + } + + for (def moduleProject : includedModuleProjects) { + loom.mods.register(moduleProject.name) { + sourceSet moduleProject.sourceSets.main + sourceSet moduleProject.sourceSets.client + } + + loom.mods.register(moduleProject.name + "-testmod") { + sourceSet moduleProject.sourceSets.testmod + sourceSet moduleProject.sourceSets.testmodClient + } + } + loom.nestJars(tasks.named("testmodJar"), nestedTestModJars) for (def moduleProject : includedModuleProjects) { From edb63c86751a1887c6456a014a603d8084516eb4 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Thu, 4 Jun 2026 21:46:19 +0100 Subject: [PATCH 03/23] Cleanup, groovy -> java --- buildSrc/build.gradle | 2 +- .../groovy/fabric-api.deprecated-bom.gradle | 2 +- .../groovy/fabric-api.meta-publishing.gradle | 2 +- .../src/main/groovy/fabric-api.module.gradle | 2 +- .../main/groovy/fabric-api.publishing.gradle | 2 +- .../src/main/groovy/fabric-api.root.gradle | 2 +- .../src/main/groovy/fabric-api.testing.gradle | 2 +- .../main/groovy/fabric-api.validation.gradle | 12 +- .../main/groovy/fabric-api.versioning.gradle | 4 +- .../fabric/build/BumpVersionTask.groovy | 116 ----------- .../fabric/build/FabricApiBuildUtils.groovy | 162 --------------- .../build/FabricApiModuleExtension.groovy | 97 --------- .../build/GeneratePackageInfosTask.groovy | 96 --------- .../build/ValidateAnnotationsTask.groovy | 30 --- .../fabric/build/ValidateModuleTask.groovy | 80 -------- .../fabric/impl/build/BumpVersionTask.java | 144 +++++++++++++ .../impl/build/FabricApiBuildUtils.java | 190 ++++++++++++++++++ .../impl/build/FabricApiModuleExtension.java | 136 +++++++++++++ .../impl/build/GeneratePackageInfosTask.java | 152 ++++++++++++++ .../impl/build/ValidateAnnotationsTask.java | 57 ++++++ .../fabric/impl/build/ValidateModuleTask.java | 105 ++++++++++ 21 files changed, 799 insertions(+), 596 deletions(-) delete mode 100644 buildSrc/src/main/groovy/net/fabricmc/fabric/build/BumpVersionTask.groovy delete mode 100644 buildSrc/src/main/groovy/net/fabricmc/fabric/build/FabricApiBuildUtils.groovy delete mode 100644 buildSrc/src/main/groovy/net/fabricmc/fabric/build/FabricApiModuleExtension.groovy delete mode 100644 buildSrc/src/main/groovy/net/fabricmc/fabric/build/GeneratePackageInfosTask.groovy delete mode 100644 buildSrc/src/main/groovy/net/fabricmc/fabric/build/ValidateAnnotationsTask.groovy delete mode 100644 buildSrc/src/main/groovy/net/fabricmc/fabric/build/ValidateModuleTask.groovy create mode 100644 buildSrc/src/main/java/net/fabricmc/fabric/impl/build/BumpVersionTask.java create mode 100644 buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiBuildUtils.java create mode 100644 buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiModuleExtension.java create mode 100644 buildSrc/src/main/java/net/fabricmc/fabric/impl/build/GeneratePackageInfosTask.java create mode 100644 buildSrc/src/main/java/net/fabricmc/fabric/impl/build/ValidateAnnotationsTask.java create mode 100644 buildSrc/src/main/java/net/fabricmc/fabric/impl/build/ValidateModuleTask.java diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index a25afd1f9d2..4c37c839bbb 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -14,7 +14,7 @@ repositories { } dependencies { - implementation "net.fabricmc:fabric-loom:1.16.2" + implementation "net.fabricmc:fabric-loom:1.17.0-alpha.19" } checkstyle { diff --git a/buildSrc/src/main/groovy/fabric-api.deprecated-bom.gradle b/buildSrc/src/main/groovy/fabric-api.deprecated-bom.gradle index 9ace1713694..d90f7f376de 100644 --- a/buildSrc/src/main/groovy/fabric-api.deprecated-bom.gradle +++ b/buildSrc/src/main/groovy/fabric-api.deprecated-bom.gradle @@ -1,4 +1,4 @@ -import net.fabricmc.fabric.build.FabricApiBuildUtils +import net.fabricmc.fabric.impl.build.FabricApiBuildUtils import org.gradle.api.publish.maven.MavenPublication plugins { diff --git a/buildSrc/src/main/groovy/fabric-api.meta-publishing.gradle b/buildSrc/src/main/groovy/fabric-api.meta-publishing.gradle index c07302620b8..6fbd10c8c69 100644 --- a/buildSrc/src/main/groovy/fabric-api.meta-publishing.gradle +++ b/buildSrc/src/main/groovy/fabric-api.meta-publishing.gradle @@ -1,4 +1,4 @@ -import net.fabricmc.fabric.build.FabricApiBuildUtils +import net.fabricmc.fabric.impl.build.FabricApiBuildUtils plugins { id "maven-publish" diff --git a/buildSrc/src/main/groovy/fabric-api.module.gradle b/buildSrc/src/main/groovy/fabric-api.module.gradle index 047799a19d2..3e28919c203 100644 --- a/buildSrc/src/main/groovy/fabric-api.module.gradle +++ b/buildSrc/src/main/groovy/fabric-api.module.gradle @@ -1,4 +1,4 @@ -import net.fabricmc.fabric.build.FabricApiModuleExtension +import net.fabricmc.fabric.impl.build.FabricApiModuleExtension plugins { id "fabric-api.versioning" diff --git a/buildSrc/src/main/groovy/fabric-api.publishing.gradle b/buildSrc/src/main/groovy/fabric-api.publishing.gradle index b8ce575ebb8..1599adb9274 100644 --- a/buildSrc/src/main/groovy/fabric-api.publishing.gradle +++ b/buildSrc/src/main/groovy/fabric-api.publishing.gradle @@ -1,4 +1,4 @@ -import net.fabricmc.fabric.build.FabricApiBuildUtils +import net.fabricmc.fabric.impl.build.FabricApiBuildUtils import org.gradle.api.publish.maven.MavenPublication plugins { diff --git a/buildSrc/src/main/groovy/fabric-api.root.gradle b/buildSrc/src/main/groovy/fabric-api.root.gradle index bd26f3287cd..0800ee0342b 100644 --- a/buildSrc/src/main/groovy/fabric-api.root.gradle +++ b/buildSrc/src/main/groovy/fabric-api.root.gradle @@ -1,5 +1,5 @@ import groovy.xml.XmlSlurper -import net.fabricmc.fabric.build.FabricApiBuildUtils +import net.fabricmc.fabric.impl.build.FabricApiBuildUtils import org.gradle.api.publish.maven.MavenPublication import org.gradle.external.javadoc.JavadocMemberLevel diff --git a/buildSrc/src/main/groovy/fabric-api.testing.gradle b/buildSrc/src/main/groovy/fabric-api.testing.gradle index c595c43b7d2..883cd77e4df 100644 --- a/buildSrc/src/main/groovy/fabric-api.testing.gradle +++ b/buildSrc/src/main/groovy/fabric-api.testing.gradle @@ -1,4 +1,4 @@ -import net.fabricmc.fabric.build.FabricApiBuildUtils +import net.fabricmc.fabric.impl.build.FabricApiBuildUtils import net.fabricmc.loom.task.ValidateMixinNameTask sourceSets { diff --git a/buildSrc/src/main/groovy/fabric-api.validation.gradle b/buildSrc/src/main/groovy/fabric-api.validation.gradle index 83d88458593..d620d25bc6a 100644 --- a/buildSrc/src/main/groovy/fabric-api.validation.gradle +++ b/buildSrc/src/main/groovy/fabric-api.validation.gradle @@ -1,6 +1,6 @@ -import net.fabricmc.fabric.build.GeneratePackageInfosTask -import net.fabricmc.fabric.build.ValidateAnnotationsTask -import net.fabricmc.fabric.build.ValidateModuleTask +import net.fabricmc.fabric.impl.build.GeneratePackageInfosTask +import net.fabricmc.fabric.impl.build.ValidateAnnotationsTask +import net.fabricmc.fabric.impl.build.ValidateModuleTask tasks.register("validateModules", ValidateModuleTask) tasks.check.dependsOn("validateModules") @@ -23,9 +23,9 @@ for (def sourceSet in [sourceSets.main, sourceSets.client]) { def task = tasks.register(taskName, GeneratePackageInfosTask) { group = 'fabric' description = "Generates package-info files for $sourceSetName packages." - sourceRoot = file("src/$sourceSetName/java") - header = rootProject.file('HEADER') - outputDir = file("src/generated/$sourceSetName") + sourceRoot.set(file("src/$sourceSetName/java")) + header.set(rootProject.file('HEADER')) + outputDir.set(file("src/generated/$sourceSetName")) } sourceSet.java.srcDir task diff --git a/buildSrc/src/main/groovy/fabric-api.versioning.gradle b/buildSrc/src/main/groovy/fabric-api.versioning.gradle index 543b762f739..48ae4ad28b9 100644 --- a/buildSrc/src/main/groovy/fabric-api.versioning.gradle +++ b/buildSrc/src/main/groovy/fabric-api.versioning.gradle @@ -1,5 +1,5 @@ -import net.fabricmc.fabric.build.BumpVersionTask -import net.fabricmc.fabric.build.FabricApiBuildUtils +import net.fabricmc.fabric.impl.build.BumpVersionTask +import net.fabricmc.fabric.impl.build.FabricApiBuildUtils if (project == rootProject) { version = FabricApiBuildUtils.rootVersion(project) diff --git a/buildSrc/src/main/groovy/net/fabricmc/fabric/build/BumpVersionTask.groovy b/buildSrc/src/main/groovy/net/fabricmc/fabric/build/BumpVersionTask.groovy deleted file mode 100644 index eb49c1c9b7a..00000000000 --- a/buildSrc/src/main/groovy/net/fabricmc/fabric/build/BumpVersionTask.groovy +++ /dev/null @@ -1,116 +0,0 @@ -package net.fabricmc.fabric.build - -import org.gradle.api.DefaultTask -import org.gradle.api.tasks.TaskAction - -abstract class BumpVersionTask extends DefaultTask { - BumpVersionTask() { - group = "publishing" - outputs.upToDateWhen { false } - } - - @TaskAction - void runTask() { - def scanner = new Scanner(System.in) - def toUpdate = [:] - - while (true) { - println "Enter module name to update, or done to continue" - def input = scanner.nextLine() - - if (input == "done") { - break - } - - if (input == "allPatch") { - project.getChildProjects().values().forEach { - if (!FabricApiBuildUtils.isFabricModule(it)) { - return - } - - toUpdate.put(it, 2) - } - - break - } - - def subProject = project.childProjects[input] ?: project.childProjects["deprecated"].childProjects[input] - - if (!subProject) { - println "Could not find project with name: $input" - continue - } - - while (true) { - println "Bump version for ${subProject.name}:" - println "0) Bump Major" - println "1) Bump Minor" - println "2) Bump Patch" - - input = scanner.nextLine() - - if (!(input in ["0", "1", "2"])) { - println "Invalid input" - continue - } - - toUpdate.put(subProject, input as Integer) - break - } - } - - while (true) { - def temp = [:] - - toUpdate.keySet().forEach { p -> - project.allprojects.each { cp -> - if (!FabricApiBuildUtils.isFabricModule(cp) || cp == project) { - return - } - - def config = cp.configurations.findByName("api") - config?.allDependencies?.forEach { dep -> - if (dep.name == p.name && !toUpdate.containsKey(cp)) { - println "Bumping patch of ${cp.name} as it depends on ${p.name}" - temp.put(cp, 2) - } - } - } - } - - if (temp.isEmpty()) { - break - } - - toUpdate.putAll(temp) - } - - def gpFile = project.file("gradle.properties") - def props = project.properties - def text = gpFile.text - - toUpdate.forEach { p, i -> - def version = props."${p.name}-version" - - if (!version) { - throw new NullPointerException("Could not find version for " + p.name) - } - - def split = version.split("\\.") - split[i] = (split[i] as Integer) + 1 - for (j in (i + 1).. $newVersion" - - text = text.replace( - "${p.name}-version=$version", - "${p.name}-version=$newVersion" - ) - } - - gpFile.text = text - } -} diff --git a/buildSrc/src/main/groovy/net/fabricmc/fabric/build/FabricApiBuildUtils.groovy b/buildSrc/src/main/groovy/net/fabricmc/fabric/build/FabricApiBuildUtils.groovy deleted file mode 100644 index dd59977388d..00000000000 --- a/buildSrc/src/main/groovy/net/fabricmc/fabric/build/FabricApiBuildUtils.groovy +++ /dev/null @@ -1,162 +0,0 @@ -package net.fabricmc.fabric.build - -import groovy.json.JsonSlurper -import groovy.util.Node -import java.security.MessageDigest -import java.net.http.HttpClient -import java.net.http.HttpRequest -import java.net.http.HttpResponse -import net.fabricmc.fabric.impl.build.CommitHashValueSource -import net.fabricmc.fabric.impl.build.GitBranchValueSource -import org.gradle.api.Project -import org.gradle.api.artifacts.dsl.RepositoryHandler -import org.gradle.api.publish.maven.MavenPom - -final class FabricApiBuildUtils { - static final Set META_PROJECTS = [ - 'deprecated', - 'fabric-api-bom', - 'fabric-api-catalog' - ] as Set - - static final List DEBUG_ARGS = [ - "-enableassertions", - "-Dmixin.debug.verify=true", - "-Dmixin.debug.countInjections=true", - "-XX:+UseZGC", - "-XX:+UseCompactObjectHeaders", - "-XX:+AlwaysPreTouch", - "-XX:+UseStringDeduplication" - ].asImmutable() - - static final List DEV_ONLY_MODULES = [ - "fabric-client-gametest-api-v1", - "fabric-gametest-api-v1" - ].asImmutable() - - private FabricApiBuildUtils() { - } - - static boolean isMetaProject(Project project) { - return META_PROJECTS.contains(project.name) - } - - static boolean isFabricModule(Project project) { - return !isMetaProject(project) - } - - static String moduleName(String notation) { - return notation.startsWith(":") ? notation.substring(1) : notation - } - - static String projectPath(String notation) { - return notation.startsWith(":") ? notation : ":${notation}" - } - - static String rootVersion(Project project) { - def branchProvider = project.providers.of(GitBranchValueSource.class) {} - def suffix = project.providers.environmentVariable("CI").present - ? branchProvider.get().replace("/", "_") - : "local" - return "${project.findProperty('version')}+${suffix}" - } - - static String moduleVersion(Project project) { - def version = project.findProperty("${project.name}-version") - - if (!version) { - throw new NullPointerException("Could not find version for " + project.name) - } - - if (!project.providers.environmentVariable("CI").present) { - return version + "+local" - } - - def hashProvider = project.providers.of(CommitHashValueSource.class) { - parameters.directory = project.name - } - - return version + "+" + hashProvider.get().substring(0, 8) + sha256Hex(project.rootProject.minecraft_version).substring(0, 2) - } - - static void setupRepositories(Project project, RepositoryHandler repositories) { - if (project.providers.environmentVariable("MAVEN_URL").present) { - repositories.maven { - url = project.providers.environmentVariable("MAVEN_URL") - credentials { - username = project.providers.environmentVariable("MAVEN_USERNAME").get() - password = project.providers.environmentVariable("MAVEN_PASSWORD").get() - } - } - } - } - - static boolean publishedArtifactExists(Project project, String projectName, String projectVersion) { - if (!project.providers.environmentVariable("MAVEN_URL").present) { - return false - } - - def artifactPath = "https://maven.fabricmc.net/net/fabricmc/fabric-api/${projectName}/${projectVersion}/${projectName}-${projectVersion}.pom" - - return HttpClient.newHttpClient().withCloseable { client -> - def request = HttpRequest.newBuilder() - .uri(URI.create(artifactPath)) - .method("HEAD", HttpRequest.BodyPublishers.noBody()) - .build() - - def response = client.send(request, HttpResponse.BodyHandlers.discarding()) - response.statusCode() == 200 - } - } - - static void addPomMetadataInformation(Project project, MavenPom pom) { - def modJsonFile = project.file("src/main/resources/fabric.mod.json") - - if (!modJsonFile.exists()) { - modJsonFile = project.file("src/client/resources/fabric.mod.json") - } - - def modJson = new JsonSlurper().parse(modJsonFile) - pom.name = modJson.name - pom.url = "https://github.com/FabricMC/fabric/tree/HEAD/${project.rootDir.relativePath(project.projectDir)}" - pom.description = modJson.description - pom.licenses { - license { - name = "Apache-2.0" - url = "https://github.com/FabricMC/fabric/blob/HEAD/LICENSE" - } - } - pom.developers { - developer { - name = "FabricMC" - url = "https://fabricmc.net/" - } - } - pom.scm { - connection = "scm:git:https://github.com/FabricMC/fabric.git" - url = "https://github.com/FabricMC/fabric" - developerConnection = "scm:git:git@github.com:FabricMC/fabric.git" - } - pom.issueManagement { - system = "GitHub" - url = "https://github.com/FabricMC/fabric/issues" - } - } - - static void appendPomDependencies(Node pomNode, List> dependencies) { - def depsNode = pomNode.appendNode("dependencies") - - for (def dep in dependencies) { - def depNode = depsNode.appendNode("dependency") - - for (def entry in dep) { - depNode.appendNode(entry.key, entry.value) - } - } - } - - private static String sha256Hex(String input) { - def digest = MessageDigest.getInstance("SHA-256").digest(input.getBytes("UTF-8")) - return digest.collect { String.format("%02x", it) }.join() - } -} diff --git a/buildSrc/src/main/groovy/net/fabricmc/fabric/build/FabricApiModuleExtension.groovy b/buildSrc/src/main/groovy/net/fabricmc/fabric/build/FabricApiModuleExtension.groovy deleted file mode 100644 index 03cf733dcef..00000000000 --- a/buildSrc/src/main/groovy/net/fabricmc/fabric/build/FabricApiModuleExtension.groovy +++ /dev/null @@ -1,97 +0,0 @@ -package net.fabricmc.fabric.build - -import org.gradle.api.Project -import org.gradle.api.publish.maven.MavenPublication - -class FabricApiModuleExtension { - final Project project - - FabricApiModuleExtension(Project project) { - this.project = project - } - - void moduleDependencies(List depNames) { - def deps = depNames.collect { project.dependencies.project(path: FabricApiBuildUtils.projectPath(it)) } - def depProjects = depNames.collect { project.rootProject.findProject(FabricApiBuildUtils.projectPath(it)) } - def clientOutputs = depProjects.collect { it.sourceSets.client.output } - - deps.each { - project.dependencies.add("api", it) - } - - clientOutputs.each { - project.dependencies.add("clientImplementation", it) - project.sourceSets.client.compileClasspath += it - project.sourceSets.client.runtimeClasspath += it - } - - project.tasks.named("compileClientJava").configure { - depProjects.each { dependsOn it.tasks.named("clientClasses") } - } - project.afterEvaluate { - project.tasks.named("compileClientJava").configure { - doFirst { - setClasspath(getClasspath().plus(project.files(depProjects.collect { - it.layout.buildDirectory.dir("classes/java/client") - }))) - } - } - project.tasks.named("compileTestmodClientJava").configure { - doFirst { - setClasspath(getClasspath().plus(project.files(depProjects.collect { - it.layout.buildDirectory.dir("classes/java/client") - }))) - } - } - } - - def depNodes = depNames.collect { - def depProject = project.rootProject.findProject(FabricApiBuildUtils.projectPath(it)) - [ - groupId: depProject.group, - artifactId: depProject.name, - version: FabricApiBuildUtils.moduleVersion(depProject), - scope: "compile" - ] - } - - project.publishing { - publications { - mavenJava(MavenPublication) { - pom.withXml { - FabricApiBuildUtils.appendPomDependencies(asNode(), depNodes) - } - } - } - } - } - - void testDependencies(List depNames) { - def deps = depNames.collect { project.dependencies.project(path: FabricApiBuildUtils.projectPath(it)) } - def depProjects = depNames.collect { project.rootProject.findProject(FabricApiBuildUtils.projectPath(it)) } - def clientOutputs = depProjects.collect { it.sourceSets.client.output } - - deps.each { - project.dependencies.add("testmodImplementation", it) - } - - clientOutputs.each { - project.dependencies.add("testmodClientImplementation", it) - project.sourceSets.testmodClient.compileClasspath += it - project.sourceSets.testmodClient.runtimeClasspath += it - } - - project.tasks.named("compileTestmodClientJava").configure { - depProjects.each { dependsOn it.tasks.named("clientClasses") } - } - project.afterEvaluate { - project.tasks.named("compileTestmodClientJava").configure { - doFirst { - setClasspath(getClasspath().plus(project.files(depProjects.collect { - it.layout.buildDirectory.dir("classes/java/client") - }))) - } - } - } - } -} diff --git a/buildSrc/src/main/groovy/net/fabricmc/fabric/build/GeneratePackageInfosTask.groovy b/buildSrc/src/main/groovy/net/fabricmc/fabric/build/GeneratePackageInfosTask.groovy deleted file mode 100644 index 6bec5028f3b..00000000000 --- a/buildSrc/src/main/groovy/net/fabricmc/fabric/build/GeneratePackageInfosTask.groovy +++ /dev/null @@ -1,96 +0,0 @@ -package net.fabricmc.fabric.build - -import java.nio.file.Files -import org.gradle.api.DefaultTask -import org.gradle.api.file.DirectoryProperty -import org.gradle.api.provider.Property -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputDirectory -import org.gradle.api.tasks.InputFile -import org.gradle.api.tasks.OutputDirectory -import org.gradle.api.tasks.SkipWhenEmpty -import org.gradle.api.tasks.TaskAction - -abstract class GeneratePackageInfosTask extends DefaultTask { - @InputFile - File header - - @Input - abstract Property getProjectName() - - @SkipWhenEmpty - @InputDirectory - final DirectoryProperty sourceRoot = project.objects.directoryProperty() - - @OutputDirectory - final DirectoryProperty outputDir = project.objects.directoryProperty() - - GeneratePackageInfosTask() { - projectName.set(project.name) - } - - @TaskAction - void run() { - def output = outputDir.get().asFile.toPath() - output.deleteDir() - def headerText = header.readLines().join("\n") - def root = sourceRoot.get().asFile.toPath() - - root.eachDirRecurse { - def containsJava = Files.list(it).withCloseable { stream -> - stream.anyMatch { path -> Files.isRegularFile(path) && path.fileName.toString().endsWith('.java') } - } - - if (!containsJava) { - return - } - - def existingPackageInfo = it.resolve('package-info.java') - if (Files.exists(existingPackageInfo)) { - if (!existingPackageInfo.text.contains("@NullMarked")) { - throw new RuntimeException("package-info.java ${existingPackageInfo} is missing @NullMarked annotation.") - } - - return - } - - def relativePath = root.relativize(it) - def target = output.resolve(relativePath) - Files.createDirectories(target) - - def packageName = relativePath.toString().replace(File.separator, '.') - - if (packageName == "net.fabricmc.fabric.api.util" && projectName.get() == "fabric-content-registries-v0") { - return - } - - def isImpl = relativePath.toString() =~ /^(net[\/\\]fabricmc[\/\\]fabric[\/\\](impl|mixin))/ - - target.resolve('package-info.java').withWriter { - if (isImpl) { - it.write("""$headerText - |/** - | * Implementation code for ${projectName.get()}. - | */ - |@ApiStatus.Internal - |@NullMarked - |package $packageName; - | - |import org.jetbrains.annotations.ApiStatus; - |import org.jspecify.annotations.NullMarked; - |""".stripMargin()) - } else { - it.write("""$headerText - |/** - | * API code for ${projectName.get()}. - | */ - |@NullMarked - |package $packageName; - | - |import org.jspecify.annotations.NullMarked; - |""".stripMargin()) - } - } - } - } -} diff --git a/buildSrc/src/main/groovy/net/fabricmc/fabric/build/ValidateAnnotationsTask.groovy b/buildSrc/src/main/groovy/net/fabricmc/fabric/build/ValidateAnnotationsTask.groovy deleted file mode 100644 index a330761c1ef..00000000000 --- a/buildSrc/src/main/groovy/net/fabricmc/fabric/build/ValidateAnnotationsTask.groovy +++ /dev/null @@ -1,30 +0,0 @@ -package net.fabricmc.fabric.build - -import org.gradle.api.tasks.SourceTask -import org.gradle.api.tasks.TaskAction - -abstract class ValidateAnnotationsTask extends SourceTask { - private static final def API_STATUS_INTERNAL = ~/@ApiStatus\.Internal/ - private static final def ENVIRONMENT = ~/@Environment/ - - @TaskAction - void run() { - for (def dir in ['api', 'impl', 'mixin', 'test']) { - getSource().matching { include "net/fabricmc/fabric/$dir/" }.forEach { - if (it.isDirectory()) { - return - } - - def contents = it.text - - if (ENVIRONMENT.matcher(contents).find()) { - throw new RuntimeException("Found @Environment annotation in file: $it") - } - - if (dir != "api" && API_STATUS_INTERNAL.matcher(contents).find()) { - throw new RuntimeException("Found @ApiStatus.Internal in implementation file: " + it) - } - } - } - } -} diff --git a/buildSrc/src/main/groovy/net/fabricmc/fabric/build/ValidateModuleTask.groovy b/buildSrc/src/main/groovy/net/fabricmc/fabric/build/ValidateModuleTask.groovy deleted file mode 100644 index 36bc2af720d..00000000000 --- a/buildSrc/src/main/groovy/net/fabricmc/fabric/build/ValidateModuleTask.groovy +++ /dev/null @@ -1,80 +0,0 @@ -package net.fabricmc.fabric.build - -import groovy.json.JsonSlurper -import org.gradle.api.DefaultTask -import org.gradle.api.GradleException -import org.gradle.api.file.RegularFileProperty -import org.gradle.api.provider.Property -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputFile -import org.gradle.api.tasks.TaskAction - -abstract class ValidateModuleTask extends DefaultTask { - @InputFile - abstract RegularFileProperty getFmj() - - @Input - abstract Property getProjectName() - - @Input - abstract Property getProjectPath() - - @Input - abstract Property getLoaderVersion() - - ValidateModuleTask() { - group = "verification" - outputs.upToDateWhen { true } - - def file = project.file("src/main/resources/fabric.mod.json") - - if (!file.exists()) { - file = project.file("src/client/resources/fabric.mod.json") - } - - fmj.set(file) - projectName.set(project.name) - projectPath.set(project.path) - loaderVersion.set(project.loader_version) - } - - @TaskAction - void validate() { - def json = new JsonSlurper().parse(fmj.get().asFile) - - if (json.custom == null) { - throw new GradleException("Module ${projectName.get()} does not have a custom value containing module lifecycle!") - } - - def moduleLifecycle = json.custom.get("fabric-api:module-lifecycle") - - if (moduleLifecycle == null) { - throw new GradleException("Module ${projectName.get()} does not have module lifecycle in custom values!") - } - - if (!(moduleLifecycle instanceof String)) { - throw new GradleException("Module ${projectName.get()} has an invalid module lifecycle value. The value must be a string but read a ${moduleLifecycle.class}") - } - - switch (moduleLifecycle) { - case "stable": - case "experimental": - break - case "deprecated": - if (!projectPath.get().startsWith(":deprecated")) { - throw new GradleException("Deprecated module ${projectName.get()} must be in the deprecated sub directory.") - } - break - default: - throw new GradleException("Module ${projectName.get()} has an invalid module lifecycle ${moduleLifecycle}") - } - - if (json.depends == null) { - throw new GradleException("Module ${projectName.get()} does not have a depends value!") - } - - if (json.depends.fabricloader != ">=${loaderVersion.get()}") { - throw new GradleException("Module ${projectName.get()} does not have a valid fabricloader value! Got \"${json.depends.fabricloader}\" but expected \">=${loaderVersion.get()}\"") - } - } -} diff --git a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/BumpVersionTask.java b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/BumpVersionTask.java new file mode 100644 index 00000000000..1145329c6cf --- /dev/null +++ b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/BumpVersionTask.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.build; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Scanner; + +import org.gradle.api.DefaultTask; +import org.gradle.api.Project; +import org.gradle.api.tasks.TaskAction; + +public abstract class BumpVersionTask extends DefaultTask { + public BumpVersionTask() { + setGroup("publishing"); + getOutputs().upToDateWhen(task -> false); + } + + @TaskAction + public void runTask() throws IOException { + var scanner = new Scanner(System.in); + var toUpdate = new LinkedHashMap(); + + while (true) { + System.out.println("Enter module name to update, or done to continue"); + String input = scanner.nextLine(); + + if (input.equals("done")) { + break; + } + + if (input.equals("allPatch")) { + getProject().getChildProjects().values().forEach(project -> { + if (FabricApiBuildUtils.isFabricModule(project)) { + toUpdate.put(project, 2); + } + }); + break; + } + + Project subProject = getProject().getChildProjects().get(input); + Project deprecatedProject = getProject().getChildProjects().get("deprecated"); + + if (subProject == null && deprecatedProject != null) { + subProject = deprecatedProject.getChildProjects().get(input); + } + + if (subProject == null) { + System.out.println("Could not find project with name: " + input); + continue; + } + + while (true) { + System.out.println("Bump version for " + subProject.getName() + ":"); + System.out.println("0) Bump Major"); + System.out.println("1) Bump Minor"); + System.out.println("2) Bump Patch"); + + input = scanner.nextLine(); + + if (!input.equals("0") && !input.equals("1") && !input.equals("2")) { + System.out.println("Invalid input"); + continue; + } + + toUpdate.put(subProject, Integer.parseInt(input)); + break; + } + } + + while (true) { + var temp = new LinkedHashMap(); + + for (Project project : toUpdate.keySet()) { + getProject().allprojects(childProject -> { + if (!FabricApiBuildUtils.isFabricModule(childProject) || childProject == getProject()) { + return; + } + + var configuration = childProject.getConfigurations().findByName("api"); + + if (configuration != null) { + configuration.getAllDependencies().forEach(dependency -> { + if (dependency.getName().equals(project.getName()) && !toUpdate.containsKey(childProject)) { + System.out.println("Bumping patch of " + childProject.getName() + " as it depends on " + project.getName()); + temp.put(childProject, 2); + } + }); + } + }); + } + + if (temp.isEmpty()) { + break; + } + + toUpdate.putAll(temp); + } + + var gradlePropertiesFile = getProject().file("gradle.properties"); + Map properties = getProject().getProperties(); + String text = java.nio.file.Files.readString(gradlePropertiesFile.toPath(), StandardCharsets.UTF_8); + + for (var entry : toUpdate.entrySet()) { + Project project = entry.getKey(); + int index = entry.getValue(); + Object versionObject = properties.get(project.getName() + "-version"); + + if (versionObject == null) { + throw new NullPointerException("Could not find version for " + project.getName()); + } + + String version = versionObject.toString(); + String[] split = version.split("\\."); + split[index] = Integer.toString(Integer.parseInt(split[index]) + 1); + + for (int i = index + 1; i < split.length; i++) { + split[i] = "0"; + } + + String newVersion = String.join(".", split); + System.out.println(project.getName() + ": " + version + " -> " + newVersion); + text = text.replace(project.getName() + "-version=" + version, project.getName() + "-version=" + newVersion); + } + + java.nio.file.Files.writeString(gradlePropertiesFile.toPath(), text, StandardCharsets.UTF_8); + } +} diff --git a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiBuildUtils.java b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiBuildUtils.java new file mode 100644 index 00000000000..a451207a237 --- /dev/null +++ b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiBuildUtils.java @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.build; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import groovy.json.JsonSlurper; +import groovy.util.Node; +import org.gradle.api.Project; +import org.gradle.api.artifacts.dsl.RepositoryHandler; +import org.gradle.api.publish.maven.MavenPom; + +public final class FabricApiBuildUtils { + public static final Set META_PROJECTS = Set.of( + "deprecated", + "fabric-api-bom", + "fabric-api-catalog" + ); + + public static final List DEBUG_ARGS = List.of( + "-enableassertions", + "-Dmixin.debug.verify=true", + "-Dmixin.debug.countInjections=true", + "-XX:+UseZGC", + "-XX:+UseCompactObjectHeaders", + "-XX:+AlwaysPreTouch", + "-XX:+UseStringDeduplication" + ); + + public static final List DEV_ONLY_MODULES = List.of( + "fabric-client-gametest-api-v1", + "fabric-gametest-api-v1" + ); + + private FabricApiBuildUtils() { + } + + public static boolean isMetaProject(Project project) { + return META_PROJECTS.contains(project.getName()); + } + + public static boolean isFabricModule(Project project) { + return !isMetaProject(project); + } + + public static String moduleName(String notation) { + return notation.startsWith(":") ? notation.substring(1) : notation; + } + + public static String projectPath(String notation) { + return notation.startsWith(":") ? notation : ":" + notation; + } + + public static String rootVersion(Project project) { + var branchProvider = project.getProviders().of(GitBranchValueSource.class, spec -> { }); + String suffix = project.getProviders().environmentVariable("CI").isPresent() + ? branchProvider.get().replace("/", "_") + : "local"; + return project.findProperty("version") + "+" + suffix; + } + + public static String moduleVersion(Project project) { + Object version = project.findProperty(project.getName() + "-version"); + + if (version == null) { + throw new NullPointerException("Could not find version for " + project.getName()); + } + + if (!project.getProviders().environmentVariable("CI").isPresent()) { + return version + "+local"; + } + + var hashProvider = project.getProviders().of(CommitHashValueSource.class, spec -> { + spec.getParameters().getDirectory().set(project.getName()); + }); + + return version + "+" + hashProvider.get().substring(0, 8) + sha256Hex(project.getRootProject().property("minecraft_version").toString()).substring(0, 2); + } + + public static void setupRepositories(Project project, RepositoryHandler repositories) { + if (project.getProviders().environmentVariable("MAVEN_URL").isPresent()) { + repositories.maven(repository -> { + repository.setUrl(project.getProviders().environmentVariable("MAVEN_URL")); + repository.credentials(credentials -> { + credentials.setUsername(project.getProviders().environmentVariable("MAVEN_USERNAME").get()); + credentials.setPassword(project.getProviders().environmentVariable("MAVEN_PASSWORD").get()); + }); + }); + } + } + + public static boolean publishedArtifactExists(Project project, String projectName, String projectVersion) throws IOException, InterruptedException { + if (!project.getProviders().environmentVariable("MAVEN_URL").isPresent()) { + return false; + } + + String artifactPath = "https://maven.fabricmc.net/net/fabricmc/fabric-api/%s/%s/%s-%s.pom".formatted(projectName, projectVersion, projectName, projectVersion); + var request = HttpRequest.newBuilder() + .uri(URI.create(artifactPath)) + .method("HEAD", HttpRequest.BodyPublishers.noBody()) + .build(); + + try (var client = HttpClient.newHttpClient()) { + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.discarding()); + return response.statusCode() == 200; + } + } + + public static void addPomMetadataInformation(Project project, MavenPom pom) { + var modJsonFile = project.file("src/main/resources/fabric.mod.json"); + + if (!modJsonFile.exists()) { + modJsonFile = project.file("src/client/resources/fabric.mod.json"); + } + + @SuppressWarnings("unchecked") + Map modJson = (Map) new JsonSlurper().parse(modJsonFile); + pom.getName().set(modJson.get("name").toString()); + pom.getUrl().set("https://github.com/FabricMC/fabric/tree/HEAD/" + project.getRootDir().toPath().relativize(project.getProjectDir().toPath())); + pom.getDescription().set(modJson.get("description").toString()); + pom.licenses(licenses -> licenses.license(license -> { + license.getName().set("Apache-2.0"); + license.getUrl().set("https://github.com/FabricMC/fabric/blob/HEAD/LICENSE"); + })); + pom.developers(developers -> developers.developer(developer -> { + developer.getName().set("FabricMC"); + developer.getUrl().set("https://fabricmc.net/"); + })); + pom.scm(scm -> { + scm.getConnection().set("scm:git:https://github.com/FabricMC/fabric.git"); + scm.getUrl().set("https://github.com/FabricMC/fabric"); + scm.getDeveloperConnection().set("scm:git:git@github.com:FabricMC/fabric.git"); + }); + pom.issueManagement(issueManagement -> { + issueManagement.getSystem().set("GitHub"); + issueManagement.getUrl().set("https://github.com/FabricMC/fabric/issues"); + }); + } + + public static void appendPomDependencies(Node pomNode, List> dependencies) { + Node depsNode = pomNode.appendNode("dependencies"); + + for (Map dependency : dependencies) { + Node depNode = depsNode.appendNode("dependency"); + + for (var entry : dependency.entrySet()) { + depNode.appendNode(entry.getKey(), entry.getValue()); + } + } + } + + private static String sha256Hex(String input) { + try { + byte[] digest = MessageDigest.getInstance("SHA-256").digest(input.getBytes(StandardCharsets.UTF_8)); + var builder = new StringBuilder(digest.length * 2); + + for (byte value : digest) { + builder.append(String.format("%02x", value)); + } + + return builder.toString(); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("Could not load SHA-256 digest", e); + } + } +} diff --git a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiModuleExtension.java b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiModuleExtension.java new file mode 100644 index 00000000000..2d1e63d5d38 --- /dev/null +++ b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiModuleExtension.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.build; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import groovy.util.Node; +import org.gradle.api.Project; +import org.gradle.api.file.FileCollection; +import org.gradle.api.plugins.JavaPluginExtension; +import org.gradle.api.publish.PublishingExtension; +import org.gradle.api.publish.maven.MavenPublication; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.SourceSetContainer; +import org.gradle.api.tasks.compile.JavaCompile; + +public class FabricApiModuleExtension { + private final Project project; + + public FabricApiModuleExtension(Project project) { + this.project = project; + } + + public void moduleDependencies(List dependencyNames) { + project.getPluginManager().withPlugin("java", plugin -> configureModuleDependencies(dependencyNames)); + } + + public void testDependencies(List dependencyNames) { + project.getPluginManager().withPlugin("java", plugin -> configureTestDependencies(dependencyNames)); + } + + private void configureModuleDependencies(List dependencyNames) { + List dependencyProjects = dependencyProjects(dependencyNames); + SourceSet clientSourceSet = sourceSets().getByName("client"); + + for (String dependencyName : dependencyNames) { + project.getDependencies().add("api", project.getDependencies().project(Map.of("path", FabricApiBuildUtils.projectPath(dependencyName)))); + } + + addDependencyClientOutputs("clientImplementation", clientSourceSet, dependencyProjects); + dependsOnDependencyClientClasses("compileClientJava", dependencyProjects); + + project.afterEvaluate(evaluatedProject -> { + addClientClassDirsToCompileTask("compileClientJava", dependencyProjects); + addClientClassDirsToCompileTask("compileTestmodClientJava", dependencyProjects); + }); + + List> dependencyNodes = new ArrayList<>(); + + for (String dependencyName : dependencyNames) { + Project dependencyProject = project.getRootProject().findProject(FabricApiBuildUtils.projectPath(dependencyName)); + var dependencyNode = new LinkedHashMap(); + dependencyNode.put("groupId", dependencyProject.getGroup().toString()); + dependencyNode.put("artifactId", dependencyProject.getName()); + dependencyNode.put("version", FabricApiBuildUtils.moduleVersion(dependencyProject)); + dependencyNode.put("scope", "compile"); + dependencyNodes.add(dependencyNode); + } + + project.getPluginManager().withPlugin("maven-publish", plugin -> project.getExtensions().configure(PublishingExtension.class, publishing -> { + publishing.getPublications().named("mavenJava", MavenPublication.class).configure(publication -> { + publication.getPom().withXml(xml -> FabricApiBuildUtils.appendPomDependencies((Node) xml.asNode(), dependencyNodes)); + }); + })); + } + + private void configureTestDependencies(List dependencyNames) { + List dependencyProjects = dependencyProjects(dependencyNames); + SourceSet testmodClientSourceSet = sourceSets().getByName("testmodClient"); + + for (String dependencyName : dependencyNames) { + project.getDependencies().add("testmodImplementation", project.getDependencies().project(Map.of("path", FabricApiBuildUtils.projectPath(dependencyName)))); + } + + addDependencyClientOutputs("testmodClientImplementation", testmodClientSourceSet, dependencyProjects); + dependsOnDependencyClientClasses("compileTestmodClientJava", dependencyProjects); + + project.afterEvaluate(evaluatedProject -> addClientClassDirsToCompileTask("compileTestmodClientJava", dependencyProjects)); + } + + private List dependencyProjects(List dependencyNames) { + return dependencyNames.stream() + .map(dependencyName -> project.getRootProject().findProject(FabricApiBuildUtils.projectPath(dependencyName))) + .toList(); + } + + private SourceSetContainer sourceSets() { + return project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets(); + } + + private void addDependencyClientOutputs(String configurationName, SourceSet sourceSet, List dependencyProjects) { + for (Project dependencyProject : dependencyProjects) { + FileCollection clientOutput = project.files( + dependencyProject.getLayout().getBuildDirectory().dir("classes/java/client"), + dependencyProject.getLayout().getBuildDirectory().dir("resources/client") + ); + project.getDependencies().add(configurationName, clientOutput); + sourceSet.setCompileClasspath(sourceSet.getCompileClasspath().plus(clientOutput)); + sourceSet.setRuntimeClasspath(sourceSet.getRuntimeClasspath().plus(clientOutput)); + } + } + + private void dependsOnDependencyClientClasses(String taskName, List dependencyProjects) { + project.getTasks().named(taskName, JavaCompile.class).configure(task -> { + for (Project dependencyProject : dependencyProjects) { + task.dependsOn(dependencyProject.getPath() + ":clientClasses"); + } + }); + } + + private void addClientClassDirsToCompileTask(String taskName, List dependencyProjects) { + project.getTasks().named(taskName, JavaCompile.class).configure(task -> task.doFirst(t -> { + List clientClassDirs = dependencyProjects.stream() + .map(dependencyProject -> dependencyProject.getLayout().getBuildDirectory().dir("classes/java/client")) + .toList(); + task.setClasspath(task.getClasspath().plus(project.files(clientClassDirs))); + })); + } +} diff --git a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/GeneratePackageInfosTask.java b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/GeneratePackageInfosTask.java new file mode 100644 index 00000000000..e1c3d37365e --- /dev/null +++ b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/GeneratePackageInfosTask.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.build; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; + +import org.gradle.api.DefaultTask; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputDirectory; +import org.gradle.api.tasks.InputFile; +import org.gradle.api.tasks.OutputDirectory; +import org.gradle.api.tasks.SkipWhenEmpty; +import org.gradle.api.tasks.TaskAction; + +public abstract class GeneratePackageInfosTask extends DefaultTask { + @InputFile + public abstract RegularFileProperty getHeader(); + + @Input + public abstract Property getProjectName(); + + @SkipWhenEmpty + @InputDirectory + public abstract DirectoryProperty getSourceRoot(); + + @OutputDirectory + public abstract DirectoryProperty getOutputDir(); + + public GeneratePackageInfosTask() { + getProjectName().set(getProject().getName()); + } + + @TaskAction + public void run() throws IOException { + Path output = getOutputDir().get().getAsFile().toPath(); + deleteDirectory(output); + String headerText = Files.readString(getHeader().get().getAsFile().toPath(), StandardCharsets.UTF_8).trim(); + Path root = getSourceRoot().get().getAsFile().toPath(); + + Files.walkFileTree(root, new SimpleFileVisitor<>() { + @Override + public FileVisitResult preVisitDirectory(Path directory, BasicFileAttributes attrs) throws IOException { + if (!containsJavaFile(directory)) { + return FileVisitResult.CONTINUE; + } + + Path existingPackageInfo = directory.resolve("package-info.java"); + + if (Files.exists(existingPackageInfo)) { + String text = Files.readString(existingPackageInfo, StandardCharsets.UTF_8); + + if (!text.contains("@NullMarked")) { + throw new RuntimeException("package-info.java " + existingPackageInfo + " is missing @NullMarked annotation."); + } + + return FileVisitResult.CONTINUE; + } + + Path relativePath = root.relativize(directory); + Path target = output.resolve(relativePath); + Files.createDirectories(target); + + String packageName = relativePath.toString().replace(java.io.File.separatorChar, '.'); + + if (packageName.equals("net.fabricmc.fabric.api.util") && getProjectName().get().equals("fabric-content-registries-v0")) { + return FileVisitResult.CONTINUE; + } + + boolean isImpl = relativePath.toString().matches("^(net[/\\\\]fabricmc[/\\\\]fabric[/\\\\](impl|mixin)).*"); + Files.writeString(target.resolve("package-info.java"), packageInfo(headerText, packageName, isImpl), StandardCharsets.UTF_8); + return FileVisitResult.CONTINUE; + } + }); + } + + private static boolean containsJavaFile(Path directory) throws IOException { + try (var stream = Files.list(directory)) { + return stream.anyMatch(path -> Files.isRegularFile(path) && path.getFileName().toString().endsWith(".java")); + } + } + + private String packageInfo(String headerText, String packageName, boolean isImpl) { + if (isImpl) { + return """ + %s + /** + * Implementation code for %s. + */ + @ApiStatus.Internal + @NullMarked + package %s; + + import org.jetbrains.annotations.ApiStatus; + import org.jspecify.annotations.NullMarked; + """.formatted(headerText, getProjectName().get(), packageName).stripIndent(); + } + + return """ + %s + /** + * API code for %s. + */ + @NullMarked + package %s; + + import org.jspecify.annotations.NullMarked; + """.formatted(headerText, getProjectName().get(), packageName).stripIndent(); + } + + private static void deleteDirectory(Path directory) throws IOException { + if (!Files.exists(directory)) { + return; + } + + Files.walkFileTree(directory, new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } + }); + } +} diff --git a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/ValidateAnnotationsTask.java b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/ValidateAnnotationsTask.java new file mode 100644 index 00000000000..3d806d1efbb --- /dev/null +++ b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/ValidateAnnotationsTask.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.build; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.regex.Pattern; + +import org.gradle.api.tasks.SourceTask; +import org.gradle.api.tasks.TaskAction; + +public abstract class ValidateAnnotationsTask extends SourceTask { + private static final Pattern API_STATUS_INTERNAL = Pattern.compile("@ApiStatus\\.Internal"); + private static final Pattern ENVIRONMENT = Pattern.compile("@Environment"); + + @TaskAction + public void run() { + for (String directory : List.of("api", "impl", "mixin", "test")) { + getSource().matching(pattern -> pattern.include("net/fabricmc/fabric/" + directory + "/**/*.java")).forEach(file -> { + if (file.isDirectory()) { + return; + } + + String contents; + + try { + contents = java.nio.file.Files.readString(file.toPath(), StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException("Could not read file: " + file, e); + } + + if (ENVIRONMENT.matcher(contents).find()) { + throw new RuntimeException("Found @Environment annotation in file: " + file); + } + + if (!directory.equals("api") && API_STATUS_INTERNAL.matcher(contents).find()) { + throw new RuntimeException("Found @ApiStatus.Internal in implementation file: " + file); + } + }); + } + } +} diff --git a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/ValidateModuleTask.java b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/ValidateModuleTask.java new file mode 100644 index 00000000000..c2b89216420 --- /dev/null +++ b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/ValidateModuleTask.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.build; + +import java.util.Map; + +import groovy.json.JsonSlurper; +import org.gradle.api.DefaultTask; +import org.gradle.api.GradleException; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputFile; +import org.gradle.api.tasks.TaskAction; + +public abstract class ValidateModuleTask extends DefaultTask { + @InputFile + public abstract RegularFileProperty getFmj(); + + @Input + public abstract Property getProjectName(); + + @Input + public abstract Property getProjectPath(); + + @Input + public abstract Property getLoaderVersion(); + + public ValidateModuleTask() { + setGroup("verification"); + getOutputs().upToDateWhen(task -> true); + + var file = getProject().file("src/main/resources/fabric.mod.json"); + + if (!file.exists()) { + file = getProject().file("src/client/resources/fabric.mod.json"); + } + + getFmj().set(file); + getProjectName().set(getProject().getName()); + getProjectPath().set(getProject().getPath()); + getLoaderVersion().set(getProject().property("loader_version").toString()); + } + + @TaskAction + public void validate() { + @SuppressWarnings("unchecked") + Map json = (Map) new JsonSlurper().parse(getFmj().get().getAsFile()); + Object customObject = json.get("custom"); + + if (customObject == null) { + throw new GradleException("Module " + getProjectName().get() + " does not have a custom value containing module lifecycle!"); + } + + @SuppressWarnings("unchecked") + Map custom = (Map) customObject; + Object moduleLifecycle = custom.get("fabric-api:module-lifecycle"); + + if (moduleLifecycle == null) { + throw new GradleException("Module " + getProjectName().get() + " does not have module lifecycle in custom values!"); + } + + if (!(moduleLifecycle instanceof String)) { + throw new GradleException("Module " + getProjectName().get() + " has an invalid module lifecycle value. The value must be a string but read a " + moduleLifecycle.getClass()); + } + + switch ((String) moduleLifecycle) { + case "stable", "experimental" -> { } + case "deprecated" -> { + if (!getProjectPath().get().startsWith(":deprecated")) { + throw new GradleException("Deprecated module " + getProjectName().get() + " must be in the deprecated sub directory."); + } + } + default -> throw new GradleException("Module " + getProjectName().get() + " has an invalid module lifecycle " + moduleLifecycle); + } + + Object dependsObject = json.get("depends"); + + if (dependsObject == null) { + throw new GradleException("Module " + getProjectName().get() + " does not have a depends value!"); + } + + @SuppressWarnings("unchecked") + Map depends = (Map) dependsObject; + String expectedLoaderVersion = ">=" + getLoaderVersion().get(); + + if (!expectedLoaderVersion.equals(depends.get("fabricloader"))) { + throw new GradleException("Module " + getProjectName().get() + " does not have a valid fabricloader value! Got \"" + depends.get("fabricloader") + "\" but expected \"" + expectedLoaderVersion + "\""); + } + } +} From 00c52fb94e0c949f7ae150f7bdcb1dd67abe4299 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Fri, 5 Jun 2026 18:15:49 +0100 Subject: [PATCH 04/23] Enable config cache --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index cb2c644e730..180612a7511 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ org.gradle.jvmargs=-Xmx1024M org.gradle.parallel=true -org.gradle.configuration-cache=false +org.gradle.configuration-cache=true version=0.150.3 minecraft_version=26.2-pre-4 From 6fce6b2f39be77b2b8f76b28d29f5da1ab5582e7 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Fri, 5 Jun 2026 18:16:33 +0100 Subject: [PATCH 05/23] Config cache fixes --- .../src/main/groovy/fabric-api.loom.gradle | 3 + .../main/groovy/fabric-api.versioning.gradle | 21 ++- .../fabric/impl/build/BumpVersionTask.java | 156 ++++++++++-------- .../impl/build/FabricApiModuleExtension.java | 22 +-- 4 files changed, 115 insertions(+), 87 deletions(-) diff --git a/buildSrc/src/main/groovy/fabric-api.loom.gradle b/buildSrc/src/main/groovy/fabric-api.loom.gradle index 3874694599b..5529d636200 100644 --- a/buildSrc/src/main/groovy/fabric-api.loom.gradle +++ b/buildSrc/src/main/groovy/fabric-api.loom.gradle @@ -7,6 +7,9 @@ plugins { loom { splitEnvironmentSourceSets() runtimeOnlyLog4j = true + runs.configureEach { + preferGradleTask = true + } } dependencies { diff --git a/buildSrc/src/main/groovy/fabric-api.versioning.gradle b/buildSrc/src/main/groovy/fabric-api.versioning.gradle index 48ae4ad28b9..bb3cebdca29 100644 --- a/buildSrc/src/main/groovy/fabric-api.versioning.gradle +++ b/buildSrc/src/main/groovy/fabric-api.versioning.gradle @@ -4,7 +4,26 @@ import net.fabricmc.fabric.impl.build.FabricApiBuildUtils if (project == rootProject) { version = FabricApiBuildUtils.rootVersion(project) logger.lifecycle("Building Fabric: " + version) - tasks.register('bumpVersions', BumpVersionTask) + def bumpVersions = tasks.register('bumpVersions', BumpVersionTask) { + gradlePropertiesFile.set(layout.projectDirectory.file("gradle.properties")) + } + + gradle.projectsEvaluated { + def moduleProjects = rootProject.allprojects.findAll { + FabricApiBuildUtils.isFabricModule(it) && it != rootProject + } + + bumpVersions.configure { + moduleNames.set(moduleProjects.collect { it.name }) + moduleVersions.set(moduleProjects.collectEntries { + [(it.name): it.findProperty("${it.name}-version").toString()] + }) + apiDependencies.set(moduleProjects.collectEntries { + def api = it.configurations.findByName("api") + [(it.name): api == null ? "" : api.allDependencies.collect { dependency -> dependency.name }.join(",")] + }) + } + } } else { version = FabricApiBuildUtils.moduleVersion(project) } diff --git a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/BumpVersionTask.java b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/BumpVersionTask.java index 1145329c6cf..4fb7b7269f8 100644 --- a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/BumpVersionTask.java +++ b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/BumpVersionTask.java @@ -19,14 +19,33 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.LinkedHashMap; -import java.util.Map; +import java.util.List; import java.util.Scanner; import org.gradle.api.DefaultTask; -import org.gradle.api.Project; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.MapProperty; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputFile; +import org.gradle.api.tasks.PathSensitive; +import org.gradle.api.tasks.PathSensitivity; import org.gradle.api.tasks.TaskAction; public abstract class BumpVersionTask extends DefaultTask { + @InputFile + @PathSensitive(PathSensitivity.NONE) + public abstract RegularFileProperty getGradlePropertiesFile(); + + @Input + public abstract ListProperty getModuleNames(); + + @Input + public abstract MapProperty getModuleVersions(); + + @Input + public abstract MapProperty getApiDependencies(); + public BumpVersionTask() { setGroup("publishing"); getOutputs().upToDateWhen(task -> false); @@ -34,8 +53,57 @@ public BumpVersionTask() { @TaskAction public void runTask() throws IOException { + var toUpdate = new LinkedHashMap(); + readInteractiveUpdates(toUpdate); + + while (true) { + var temp = new LinkedHashMap(); + + for (String projectName : toUpdate.keySet()) { + getApiDependencies().get().forEach((childProjectName, dependencies) -> { + if (containsDependency(dependencies, projectName) && !toUpdate.containsKey(childProjectName)) { + System.out.println("Bumping patch of " + childProjectName + " as it depends on " + projectName); + temp.put(childProjectName, 2); + } + }); + } + + if (temp.isEmpty()) { + break; + } + + toUpdate.putAll(temp); + } + + var gradlePropertiesFile = getGradlePropertiesFile().get().getAsFile(); + String text = java.nio.file.Files.readString(gradlePropertiesFile.toPath(), StandardCharsets.UTF_8); + + for (var entry : toUpdate.entrySet()) { + String projectName = entry.getKey(); + int index = entry.getValue(); + String version = getModuleVersions().get().get(projectName); + + if (version == null) { + throw new NullPointerException("Could not find version for " + projectName); + } + + String[] split = version.split("\\."); + split[index] = Integer.toString(Integer.parseInt(split[index]) + 1); + + for (int i = index + 1; i < split.length; i++) { + split[i] = "0"; + } + + String newVersion = String.join(".", split); + System.out.println(projectName + ": " + version + " -> " + newVersion); + text = text.replace(projectName + "-version=" + version, projectName + "-version=" + newVersion); + } + + java.nio.file.Files.writeString(gradlePropertiesFile.toPath(), text, StandardCharsets.UTF_8); + } + + private void readInteractiveUpdates(LinkedHashMap toUpdate) { var scanner = new Scanner(System.in); - var toUpdate = new LinkedHashMap(); while (true) { System.out.println("Enter module name to update, or done to continue"); @@ -46,99 +114,41 @@ public void runTask() throws IOException { } if (input.equals("allPatch")) { - getProject().getChildProjects().values().forEach(project -> { - if (FabricApiBuildUtils.isFabricModule(project)) { - toUpdate.put(project, 2); - } - }); + getModuleNames().get().forEach(moduleName -> toUpdate.put(moduleName, 2)); break; } - Project subProject = getProject().getChildProjects().get(input); - Project deprecatedProject = getProject().getChildProjects().get("deprecated"); - - if (subProject == null && deprecatedProject != null) { - subProject = deprecatedProject.getChildProjects().get(input); - } - - if (subProject == null) { + if (!getModuleNames().get().contains(input)) { System.out.println("Could not find project with name: " + input); continue; } while (true) { - System.out.println("Bump version for " + subProject.getName() + ":"); + System.out.println("Bump version for " + input + ":"); System.out.println("0) Bump Major"); System.out.println("1) Bump Minor"); System.out.println("2) Bump Patch"); - input = scanner.nextLine(); + String bump = scanner.nextLine(); - if (!input.equals("0") && !input.equals("1") && !input.equals("2")) { + if (!bump.equals("0") && !bump.equals("1") && !bump.equals("2")) { System.out.println("Invalid input"); continue; } - toUpdate.put(subProject, Integer.parseInt(input)); + toUpdate.put(input, Integer.parseInt(bump)); break; } } + } - while (true) { - var temp = new LinkedHashMap(); - - for (Project project : toUpdate.keySet()) { - getProject().allprojects(childProject -> { - if (!FabricApiBuildUtils.isFabricModule(childProject) || childProject == getProject()) { - return; - } - - var configuration = childProject.getConfigurations().findByName("api"); - - if (configuration != null) { - configuration.getAllDependencies().forEach(dependency -> { - if (dependency.getName().equals(project.getName()) && !toUpdate.containsKey(childProject)) { - System.out.println("Bumping patch of " + childProject.getName() + " as it depends on " + project.getName()); - temp.put(childProject, 2); - } - }); - } - }); - } - - if (temp.isEmpty()) { - break; - } - - toUpdate.putAll(temp); - } - - var gradlePropertiesFile = getProject().file("gradle.properties"); - Map properties = getProject().getProperties(); - String text = java.nio.file.Files.readString(gradlePropertiesFile.toPath(), StandardCharsets.UTF_8); - - for (var entry : toUpdate.entrySet()) { - Project project = entry.getKey(); - int index = entry.getValue(); - Object versionObject = properties.get(project.getName() + "-version"); - - if (versionObject == null) { - throw new NullPointerException("Could not find version for " + project.getName()); - } - - String version = versionObject.toString(); - String[] split = version.split("\\."); - split[index] = Integer.toString(Integer.parseInt(split[index]) + 1); - - for (int i = index + 1; i < split.length; i++) { - split[i] = "0"; + private static boolean containsDependency(String dependencies, String projectName) { + for (String dependency : dependencies.split(",")) { + if (dependency.equals(projectName)) { + return true; } - - String newVersion = String.join(".", split); - System.out.println(project.getName() + ": " + version + " -> " + newVersion); - text = text.replace(project.getName() + "-version=" + version, project.getName() + "-version=" + newVersion); } - java.nio.file.Files.writeString(gradlePropertiesFile.toPath(), text, StandardCharsets.UTF_8); + return false; } } diff --git a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiModuleExtension.java b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiModuleExtension.java index 2d1e63d5d38..ed6e487044c 100644 --- a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiModuleExtension.java +++ b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiModuleExtension.java @@ -56,11 +56,8 @@ private void configureModuleDependencies(List dependencyNames) { addDependencyClientOutputs("clientImplementation", clientSourceSet, dependencyProjects); dependsOnDependencyClientClasses("compileClientJava", dependencyProjects); - - project.afterEvaluate(evaluatedProject -> { - addClientClassDirsToCompileTask("compileClientJava", dependencyProjects); - addClientClassDirsToCompileTask("compileTestmodClientJava", dependencyProjects); - }); + addClientClassDirsToCompileTask("compileClientJava", dependencyProjects); + addClientClassDirsToCompileTask("compileTestmodClientJava", dependencyProjects); List> dependencyNodes = new ArrayList<>(); @@ -91,8 +88,7 @@ private void configureTestDependencies(List dependencyNames) { addDependencyClientOutputs("testmodClientImplementation", testmodClientSourceSet, dependencyProjects); dependsOnDependencyClientClasses("compileTestmodClientJava", dependencyProjects); - - project.afterEvaluate(evaluatedProject -> addClientClassDirsToCompileTask("compileTestmodClientJava", dependencyProjects)); + addClientClassDirsToCompileTask("compileTestmodClientJava", dependencyProjects); } private List dependencyProjects(List dependencyNames) { @@ -126,11 +122,11 @@ private void dependsOnDependencyClientClasses(String taskName, List dep } private void addClientClassDirsToCompileTask(String taskName, List dependencyProjects) { - project.getTasks().named(taskName, JavaCompile.class).configure(task -> task.doFirst(t -> { - List clientClassDirs = dependencyProjects.stream() - .map(dependencyProject -> dependencyProject.getLayout().getBuildDirectory().dir("classes/java/client")) - .toList(); - task.setClasspath(task.getClasspath().plus(project.files(clientClassDirs))); - })); + List clientClassDirs = dependencyProjects.stream() + .map(dependencyProject -> dependencyProject.getLayout().getBuildDirectory().dir("classes/java/client")) + .toList(); + FileCollection clientClasses = project.files(clientClassDirs); + + project.getTasks().named(taskName, JavaCompile.class).configure(task -> task.setClasspath(task.getClasspath().plus(clientClasses))); } } From a50909cab52997574817fc23b6100b4567684b09 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Fri, 5 Jun 2026 18:19:21 +0100 Subject: [PATCH 06/23] Cleanup --- .../src/main/groovy/fabric-api.testing.gradle | 15 ++++++++++++--- .../fabric/impl/build/FabricApiBuildUtils.java | 10 ---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/buildSrc/src/main/groovy/fabric-api.testing.gradle b/buildSrc/src/main/groovy/fabric-api.testing.gradle index 883cd77e4df..c620c42a446 100644 --- a/buildSrc/src/main/groovy/fabric-api.testing.gradle +++ b/buildSrc/src/main/groovy/fabric-api.testing.gradle @@ -1,6 +1,15 @@ -import net.fabricmc.fabric.impl.build.FabricApiBuildUtils import net.fabricmc.loom.task.ValidateMixinNameTask +def debugArgs = [ + "-enableassertions", + "-Dmixin.debug.verify=true", + "-Dmixin.debug.countInjections=true", + "-XX:+UseZGC", + "-XX:+UseCompactObjectHeaders", + "-XX:+AlwaysPreTouch", + "-XX:+UseStringDeduplication" +] + sourceSets { testmod { compileClasspath += main.compileClasspath @@ -41,7 +50,7 @@ loom { } loom.runs.configureEach { - vmArgs(FabricApiBuildUtils.DEBUG_ARGS) + vmArgs(debugArgs) } dependencies { @@ -57,7 +66,7 @@ dependencies { test { useJUnitPlatform() - jvmArgs(FabricApiBuildUtils.DEBUG_ARGS) + jvmArgs(debugArgs) } tasks.register('testmodJar', Jar) { diff --git a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiBuildUtils.java b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiBuildUtils.java index a451207a237..b0c373db4ea 100644 --- a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiBuildUtils.java +++ b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiBuildUtils.java @@ -41,16 +41,6 @@ public final class FabricApiBuildUtils { "fabric-api-catalog" ); - public static final List DEBUG_ARGS = List.of( - "-enableassertions", - "-Dmixin.debug.verify=true", - "-Dmixin.debug.countInjections=true", - "-XX:+UseZGC", - "-XX:+UseCompactObjectHeaders", - "-XX:+AlwaysPreTouch", - "-XX:+UseStringDeduplication" - ); - public static final List DEV_ONLY_MODULES = List.of( "fabric-client-gametest-api-v1", "fabric-gametest-api-v1" From 85f9eeba0a775147ca21a58c333f83f8da8a8f87 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Fri, 5 Jun 2026 18:23:03 +0100 Subject: [PATCH 07/23] Improve dsl --- .../impl/build/FabricApiModuleExtension.java | 8 ++--- .../fabric-resource-loader-v0/build.gradle | 18 +++++++---- fabric-api-base/build.gradle | 12 ++++--- fabric-api-lookup-api-v1/build.gradle | 20 ++++++------ fabric-biome-api-v1/build.gradle | 14 ++++---- fabric-block-api-v1/build.gradle | 8 +++-- fabric-command-api-v2/build.gradle | 12 ++++--- fabric-content-registries-v0/build.gradle | 12 ++++--- fabric-convention-tags-v2/build.gradle | 16 ++++++---- fabric-crash-report-info-v1/build.gradle | 8 +++-- fabric-creative-tab-api-v1/build.gradle | 10 +++--- fabric-data-attachment-api-v1/build.gradle | 30 +++++++++-------- fabric-data-generation-api-v1/build.gradle | 26 ++++++++------- fabric-debug-api-v1/build.gradle | 11 ++++--- fabric-dimensions-v1/build.gradle | 18 ++++++----- fabric-entity-events-v1/build.gradle | 18 +++++++---- fabric-events-interaction-v0/build.gradle | 12 ++++--- fabric-game-rule-api-v1/build.gradle | 16 ++++++---- fabric-gametest-api-v1/build.gradle | 12 ++++--- fabric-item-api-v1/build.gradle | 12 ++++--- fabric-key-mapping-api-v1/build.gradle | 12 ++++--- fabric-lifecycle-events-v1/build.gradle | 6 +++- fabric-loot-api-v3/build.gradle | 10 +++--- fabric-menu-api-v1/build.gradle | 22 +++++++------ fabric-message-api-v1/build.gradle | 10 ++++-- fabric-model-loading-api-v1/build.gradle | 22 +++++++------ fabric-networking-api-v1/build.gradle | 16 ++++++---- fabric-object-builder-api-v1/build.gradle | 22 +++++++------ fabric-particles-v1/build.gradle | 14 ++++---- fabric-permission-api-v1/build.gradle | 18 ++++++----- fabric-recipe-api-v1/build.gradle | 18 ++++++----- fabric-registry-sync-v0/build.gradle | 18 ++++++----- fabric-renderer-api-v1/build.gradle | 32 ++++++++++--------- fabric-renderer-indigo/build.gradle | 12 ++++--- fabric-rendering-fluids-v1/build.gradle | 6 +++- fabric-rendering-v1/build.gradle | 24 +++++++------- .../build.gradle | 10 +++--- fabric-resource-loader-v1/build.gradle | 20 +++++++----- fabric-screen-api-v1/build.gradle | 6 +++- fabric-sound-api-v1/build.gradle | 12 ++++--- fabric-tag-api-v1/build.gradle | 22 +++++++------ fabric-transfer-api-v1/build.gradle | 28 ++++++++-------- .../build.gradle | 11 ++++--- 43 files changed, 386 insertions(+), 278 deletions(-) diff --git a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiModuleExtension.java b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiModuleExtension.java index ed6e487044c..b58bf61ca5b 100644 --- a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiModuleExtension.java +++ b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiModuleExtension.java @@ -38,12 +38,12 @@ public FabricApiModuleExtension(Project project) { this.project = project; } - public void moduleDependencies(List dependencyNames) { - project.getPluginManager().withPlugin("java", plugin -> configureModuleDependencies(dependencyNames)); + public void moduleDependencies(String... dependencyNames) { + project.getPluginManager().withPlugin("java", plugin -> configureModuleDependencies(List.of(dependencyNames))); } - public void testDependencies(List dependencyNames) { - project.getPluginManager().withPlugin("java", plugin -> configureTestDependencies(dependencyNames)); + public void testDependencies(String... dependencyNames) { + project.getPluginManager().withPlugin("java", plugin -> configureTestDependencies(List.of(dependencyNames))); } private void configureModuleDependencies(List dependencyNames) { diff --git a/deprecated/fabric-resource-loader-v0/build.gradle b/deprecated/fabric-resource-loader-v0/build.gradle index ed0d91c0454..e4ea818fb85 100644 --- a/deprecated/fabric-resource-loader-v0/build.gradle +++ b/deprecated/fabric-resource-loader-v0/build.gradle @@ -2,11 +2,15 @@ plugins { id 'fabric-api.module' } -fabricApiModule.moduleDependencies(['fabric-api-base', 'fabric-resource-loader-v1']) +fabricApiModule { + moduleDependencies( + 'fabric-api-base', 'fabric-resource-loader-v1' + ) -fabricApiModule.testDependencies([ - ':fabric-lifecycle-events-v1', - ':fabric-api-base', - ':fabric-gametest-api-v1', - ':deprecated:fabric-resource-loader-v0' -]) + testDependencies( + ':fabric-lifecycle-events-v1', + ':fabric-api-base', + ':fabric-gametest-api-v1', + ':deprecated:fabric-resource-loader-v0' + ) +} diff --git a/fabric-api-base/build.gradle b/fabric-api-base/build.gradle index 6774e35e997..bacb253c889 100644 --- a/fabric-api-base/build.gradle +++ b/fabric-api-base/build.gradle @@ -2,8 +2,10 @@ plugins { id 'fabric-api.module' } -fabricApiModule.testDependencies([ - ':fabric-command-api-v2', - ':fabric-lifecycle-events-v1', - ':fabric-screen-api-v1' -]) +fabricApiModule { + testDependencies( + ':fabric-command-api-v2', + ':fabric-lifecycle-events-v1', + ':fabric-screen-api-v1' + ) +} diff --git a/fabric-api-lookup-api-v1/build.gradle b/fabric-api-lookup-api-v1/build.gradle index c8e44af3398..8a6a136a089 100644 --- a/fabric-api-lookup-api-v1/build.gradle +++ b/fabric-api-lookup-api-v1/build.gradle @@ -2,13 +2,15 @@ plugins { id 'fabric-api.module' } -fabricApiModule.moduleDependencies([ - 'fabric-api-base', - 'fabric-lifecycle-events-v1' -]) +fabricApiModule { + moduleDependencies( + 'fabric-api-base', + 'fabric-lifecycle-events-v1' + ) -fabricApiModule.testDependencies([ - ':fabric-rendering-v1', - ':fabric-object-builder-api-v1', - ':fabric-transitive-access-wideners-v1' -]) + testDependencies( + ':fabric-rendering-v1', + ':fabric-object-builder-api-v1', + ':fabric-transitive-access-wideners-v1' + ) +} diff --git a/fabric-biome-api-v1/build.gradle b/fabric-biome-api-v1/build.gradle index dd7c3043aa0..7f8dcaf6630 100644 --- a/fabric-biome-api-v1/build.gradle +++ b/fabric-biome-api-v1/build.gradle @@ -6,12 +6,14 @@ loom { accessWidenerPath = file("src/main/resources/fabric-biome-api-v1.classtweaker") } -fabricApiModule.testDependencies([ - ':fabric-api-base', - ':fabric-resource-loader-v1', - ':fabric-registry-sync-v0', - ':fabric-data-generation-api-v1' -]) +fabricApiModule { + testDependencies( + ':fabric-api-base', + ':fabric-resource-loader-v1', + ':fabric-registry-sync-v0', + ':fabric-data-generation-api-v1' + ) +} fabricApi { configureDataGeneration { diff --git a/fabric-block-api-v1/build.gradle b/fabric-block-api-v1/build.gradle index 599ea9c0309..c3b1b47059b 100644 --- a/fabric-block-api-v1/build.gradle +++ b/fabric-block-api-v1/build.gradle @@ -6,6 +6,8 @@ loom { accessWidenerPath = file('src/main/resources/fabric-block-api-v1.classtweaker') } -fabricApiModule.testDependencies([ - ':fabric-rendering-v1', -]) +fabricApiModule { + testDependencies( + ':fabric-rendering-v1', + ) +} diff --git a/fabric-command-api-v2/build.gradle b/fabric-command-api-v2/build.gradle index 3453a53b29d..3f23f875b9e 100644 --- a/fabric-command-api-v2/build.gradle +++ b/fabric-command-api-v2/build.gradle @@ -2,11 +2,15 @@ plugins { id 'fabric-api.module' } -fabricApiModule.moduleDependencies(['fabric-api-base']) +fabricApiModule { + moduleDependencies( + 'fabric-api-base' + ) -fabricApiModule.testDependencies([ - ':fabric-lifecycle-events-v1', -]) + testDependencies( + ':fabric-lifecycle-events-v1', + ) +} loom { accessWidenerPath = file('src/main/resources/fabric-command-api-v2.classtweaker') diff --git a/fabric-content-registries-v0/build.gradle b/fabric-content-registries-v0/build.gradle index c1ad1045ea5..e54b688847d 100644 --- a/fabric-content-registries-v0/build.gradle +++ b/fabric-content-registries-v0/build.gradle @@ -6,8 +6,10 @@ loom { accessWidenerPath = file("src/main/resources/fabric-content-registries-v0.classtweaker") } -fabricApiModule.moduleDependencies([ - 'fabric-api-base', - 'fabric-lifecycle-events-v1', - 'fabric-resource-loader-v1' -]) +fabricApiModule { + moduleDependencies( + 'fabric-api-base', + 'fabric-lifecycle-events-v1', + 'fabric-resource-loader-v1' + ) +} diff --git a/fabric-convention-tags-v2/build.gradle b/fabric-convention-tags-v2/build.gradle index a18af841b27..587af7fbb9e 100644 --- a/fabric-convention-tags-v2/build.gradle +++ b/fabric-convention-tags-v2/build.gradle @@ -6,14 +6,16 @@ loom { accessWidenerPath = file('src/main/resources/fabric-convention-tags-v2.classtweaker') } -fabricApiModule.moduleDependencies([ - 'fabric-api-base', - 'fabric-lifecycle-events-v1' -]) +fabricApiModule { + moduleDependencies( + 'fabric-api-base', + 'fabric-lifecycle-events-v1' + ) -fabricApiModule.testDependencies([ - ':fabric-lifecycle-events-v1', -]) + testDependencies( + ':fabric-lifecycle-events-v1', + ) +} fabricApi { configureDataGeneration { diff --git a/fabric-crash-report-info-v1/build.gradle b/fabric-crash-report-info-v1/build.gradle index 4d72ffd3f06..ecf1ef16bbe 100644 --- a/fabric-crash-report-info-v1/build.gradle +++ b/fabric-crash-report-info-v1/build.gradle @@ -2,6 +2,8 @@ plugins { id 'fabric-api.module' } -fabricApiModule.testDependencies([ - ':fabric-command-api-v2' -]) +fabricApiModule { + testDependencies( + ':fabric-command-api-v2' + ) +} diff --git a/fabric-creative-tab-api-v1/build.gradle b/fabric-creative-tab-api-v1/build.gradle index 3560d5d9215..326b92d1f88 100644 --- a/fabric-creative-tab-api-v1/build.gradle +++ b/fabric-creative-tab-api-v1/build.gradle @@ -2,10 +2,12 @@ plugins { id 'fabric-api.module' } -fabricApiModule.moduleDependencies([ - 'fabric-api-base', - 'fabric-resource-loader-v1' -]) +fabricApiModule { + moduleDependencies( + 'fabric-api-base', + 'fabric-resource-loader-v1' + ) +} loom { accessWidenerPath = file('src/main/resources/fabric-creative-tab-api-v1.classtweaker') diff --git a/fabric-data-attachment-api-v1/build.gradle b/fabric-data-attachment-api-v1/build.gradle index 1456144a71d..b53949d440a 100644 --- a/fabric-data-attachment-api-v1/build.gradle +++ b/fabric-data-attachment-api-v1/build.gradle @@ -6,18 +6,20 @@ loom { accessWidenerPath = file('src/main/resources/fabric-data-attachment-api-v1.classtweaker') } -fabricApiModule.moduleDependencies([ - 'fabric-api-base', - ':fabric-entity-events-v1', - ':fabric-object-builder-api-v1', - ':fabric-networking-api-v1' -]) +fabricApiModule { + moduleDependencies( + 'fabric-api-base', + ':fabric-entity-events-v1', + ':fabric-object-builder-api-v1', + ':fabric-networking-api-v1' + ) -fabricApiModule.testDependencies([ - ':fabric-lifecycle-events-v1', - ':fabric-biome-api-v1', - ':fabric-command-api-v2', - ':fabric-rendering-v1', - ':fabric-client-gametest-api-v1', - ':fabric-events-interaction-v0', -]) + testDependencies( + ':fabric-lifecycle-events-v1', + ':fabric-biome-api-v1', + ':fabric-command-api-v2', + ':fabric-rendering-v1', + ':fabric-client-gametest-api-v1', + ':fabric-events-interaction-v0', + ) +} diff --git a/fabric-data-generation-api-v1/build.gradle b/fabric-data-generation-api-v1/build.gradle index 0a3ba4ae711..1b5dd36b227 100644 --- a/fabric-data-generation-api-v1/build.gradle +++ b/fabric-data-generation-api-v1/build.gradle @@ -2,18 +2,20 @@ plugins { id 'fabric-api.module' } -fabricApiModule.moduleDependencies([ - 'fabric-convention-tags-v2', - 'fabric-recipe-api-v1', - 'fabric-registry-sync-v0', - 'fabric-resource-conditions-api-v1', - 'fabric-tag-api-v1', -]) - -fabricApiModule.testDependencies([ - ':fabric-creative-tab-api-v1', - ':fabric-object-builder-api-v1' -]) +fabricApiModule { + moduleDependencies( + 'fabric-convention-tags-v2', + 'fabric-recipe-api-v1', + 'fabric-registry-sync-v0', + 'fabric-resource-conditions-api-v1', + 'fabric-tag-api-v1', + ) + + testDependencies( + ':fabric-creative-tab-api-v1', + ':fabric-object-builder-api-v1' + ) +} dependencies { } diff --git a/fabric-debug-api-v1/build.gradle b/fabric-debug-api-v1/build.gradle index de944a6384e..2b682681b0a 100644 --- a/fabric-debug-api-v1/build.gradle +++ b/fabric-debug-api-v1/build.gradle @@ -2,12 +2,13 @@ plugins { id 'fabric-api.module' } -fabricApiModule.moduleDependencies([ - 'fabric-api-base' -]) +fabricApiModule { + moduleDependencies( + 'fabric-api-base' + ) -fabricApiModule.testDependencies([ -]) + testDependencies() +} loom { accessWidenerPath = file("src/main/resources/fabric-debug-api-v1.accesswidener") diff --git a/fabric-dimensions-v1/build.gradle b/fabric-dimensions-v1/build.gradle index 47adaa47462..44abeeac62b 100644 --- a/fabric-dimensions-v1/build.gradle +++ b/fabric-dimensions-v1/build.gradle @@ -2,12 +2,14 @@ plugins { id 'fabric-api.module' } -fabricApiModule.moduleDependencies([ - 'fabric-api-base', - 'fabric-lifecycle-events-v1' -]) +fabricApiModule { + moduleDependencies( + 'fabric-api-base', + 'fabric-lifecycle-events-v1' + ) -fabricApiModule.testDependencies([ - ':fabric-resource-loader-v1', - ':fabric-client-gametest-api-v1' -]) + testDependencies( + ':fabric-resource-loader-v1', + ':fabric-client-gametest-api-v1' + ) +} diff --git a/fabric-entity-events-v1/build.gradle b/fabric-entity-events-v1/build.gradle index 5fce111f2bf..2f81a2d7758 100644 --- a/fabric-entity-events-v1/build.gradle +++ b/fabric-entity-events-v1/build.gradle @@ -6,11 +6,15 @@ loom { accessWidenerPath = file('src/main/resources/fabric-entity-events-v1.classtweaker') } -fabricApiModule.moduleDependencies(['fabric-api-base']) +fabricApiModule { + moduleDependencies( + 'fabric-api-base' + ) -fabricApiModule.testDependencies([ - ':fabric-command-api-v2', - ':fabric-networking-api-v1', - ':fabric-registry-sync-v0', - ':fabric-rendering-v1' -]) + testDependencies( + ':fabric-command-api-v2', + ':fabric-networking-api-v1', + ':fabric-registry-sync-v0', + ':fabric-rendering-v1' + ) +} diff --git a/fabric-events-interaction-v0/build.gradle b/fabric-events-interaction-v0/build.gradle index 4ea272fffc1..bdf9d896202 100644 --- a/fabric-events-interaction-v0/build.gradle +++ b/fabric-events-interaction-v0/build.gradle @@ -2,8 +2,12 @@ plugins { id 'fabric-api.module' } -fabricApiModule.moduleDependencies(['fabric-api-base', 'fabric-networking-api-v1']) +fabricApiModule { + moduleDependencies( + 'fabric-api-base', 'fabric-networking-api-v1' + ) -fabricApiModule.testDependencies([ - 'fabric-client-gametest-api-v1' -]) + testDependencies( + 'fabric-client-gametest-api-v1' + ) +} diff --git a/fabric-game-rule-api-v1/build.gradle b/fabric-game-rule-api-v1/build.gradle index 6733ed43473..d831fdfcdc9 100644 --- a/fabric-game-rule-api-v1/build.gradle +++ b/fabric-game-rule-api-v1/build.gradle @@ -6,10 +6,14 @@ loom { accessWidenerPath = file("src/main/resources/fabric-game-rule-api-v1.classtweaker") } -fabricApiModule.moduleDependencies(['fabric-api-base']) +fabricApiModule { + moduleDependencies( + 'fabric-api-base' + ) -fabricApiModule.testDependencies([ - ':fabric-api-base', - ':fabric-lifecycle-events-v1', - ':fabric-resource-loader-v1' -]) + testDependencies( + ':fabric-api-base', + ':fabric-lifecycle-events-v1', + ':fabric-resource-loader-v1' + ) +} diff --git a/fabric-gametest-api-v1/build.gradle b/fabric-gametest-api-v1/build.gradle index 4360925efbf..8e499012b17 100644 --- a/fabric-gametest-api-v1/build.gradle +++ b/fabric-gametest-api-v1/build.gradle @@ -17,8 +17,10 @@ loom { } } -fabricApiModule.moduleDependencies([ - 'fabric-api-base', - 'fabric-registry-sync-v0', - 'fabric-resource-loader-v1', -]) +fabricApiModule { + moduleDependencies( + 'fabric-api-base', + 'fabric-registry-sync-v0', + 'fabric-resource-loader-v1', + ) +} diff --git a/fabric-item-api-v1/build.gradle b/fabric-item-api-v1/build.gradle index 153c031f4e1..6dd9613f946 100644 --- a/fabric-item-api-v1/build.gradle +++ b/fabric-item-api-v1/build.gradle @@ -6,8 +6,12 @@ loom { accessWidenerPath = file("src/main/resources/fabric-item-api-v1.classtweaker") } -fabricApiModule.moduleDependencies(['fabric-api-base', 'fabric-resource-loader-v1']) +fabricApiModule { + moduleDependencies( + 'fabric-api-base', 'fabric-resource-loader-v1' + ) -fabricApiModule.testDependencies([ - ':fabric-content-registries-v0', -]) + testDependencies( + ':fabric-content-registries-v0', + ) +} diff --git a/fabric-key-mapping-api-v1/build.gradle b/fabric-key-mapping-api-v1/build.gradle index be3dcaba85c..732c893ca7a 100644 --- a/fabric-key-mapping-api-v1/build.gradle +++ b/fabric-key-mapping-api-v1/build.gradle @@ -2,8 +2,10 @@ plugins { id 'fabric-api.module' } -fabricApiModule.testDependencies([ - ':fabric-api-base', - ':fabric-lifecycle-events-v1', - ':fabric-resource-loader-v1' -]) +fabricApiModule { + testDependencies( + ':fabric-api-base', + ':fabric-lifecycle-events-v1', + ':fabric-resource-loader-v1' + ) +} diff --git a/fabric-lifecycle-events-v1/build.gradle b/fabric-lifecycle-events-v1/build.gradle index 810b28943cb..205f91188ba 100644 --- a/fabric-lifecycle-events-v1/build.gradle +++ b/fabric-lifecycle-events-v1/build.gradle @@ -6,4 +6,8 @@ loom { accessWidenerPath = file("src/main/resources/fabric-lifecycle-events-v1.classtweaker") } -fabricApiModule.moduleDependencies(['fabric-api-base']) +fabricApiModule { + moduleDependencies( + 'fabric-api-base' + ) +} diff --git a/fabric-loot-api-v3/build.gradle b/fabric-loot-api-v3/build.gradle index 319831f153b..8864f5039d2 100644 --- a/fabric-loot-api-v3/build.gradle +++ b/fabric-loot-api-v3/build.gradle @@ -6,7 +6,9 @@ loom { accessWidenerPath = file('src/main/resources/fabric-loot-api-v3.classtweaker') } -fabricApiModule.moduleDependencies([ - 'fabric-api-base', - 'fabric-resource-loader-v1' -]) +fabricApiModule { + moduleDependencies( + 'fabric-api-base', + 'fabric-resource-loader-v1' + ) +} diff --git a/fabric-menu-api-v1/build.gradle b/fabric-menu-api-v1/build.gradle index 60ab64e6984..94f1375197a 100644 --- a/fabric-menu-api-v1/build.gradle +++ b/fabric-menu-api-v1/build.gradle @@ -6,14 +6,16 @@ loom { accessWidenerPath = file('src/main/resources/fabric-menu-api-v1.classtweaker') } -fabricApiModule.moduleDependencies([ - 'fabric-api-base', - 'fabric-networking-api-v1', - 'fabric-registry-sync-v0' -]) +fabricApiModule { + moduleDependencies( + 'fabric-api-base', + 'fabric-networking-api-v1', + 'fabric-registry-sync-v0' + ) -fabricApiModule.testDependencies([ - ':fabric-object-builder-api-v1', - ':fabric-resource-loader-v1', - ':fabric-transitive-access-wideners-v1' -]) + testDependencies( + ':fabric-object-builder-api-v1', + ':fabric-resource-loader-v1', + ':fabric-transitive-access-wideners-v1' + ) +} diff --git a/fabric-message-api-v1/build.gradle b/fabric-message-api-v1/build.gradle index f8486b9faa4..365271edb25 100644 --- a/fabric-message-api-v1/build.gradle +++ b/fabric-message-api-v1/build.gradle @@ -2,6 +2,12 @@ plugins { id 'fabric-api.module' } -fabricApiModule.moduleDependencies(['fabric-api-base']) +fabricApiModule { + moduleDependencies( + 'fabric-api-base' + ) -fabricApiModule.testDependencies(['fabric-command-api-v2']) + testDependencies( + 'fabric-command-api-v2' + ) +} diff --git a/fabric-model-loading-api-v1/build.gradle b/fabric-model-loading-api-v1/build.gradle index a9ae716c9e4..853f589aa64 100644 --- a/fabric-model-loading-api-v1/build.gradle +++ b/fabric-model-loading-api-v1/build.gradle @@ -2,17 +2,19 @@ plugins { id 'fabric-api.module' } -fabricApiModule.moduleDependencies([ - 'fabric-api-base', - 'fabric-renderer-api-v1' -]) +fabricApiModule { + moduleDependencies( + 'fabric-api-base', + 'fabric-renderer-api-v1' + ) -fabricApiModule.testDependencies([ - ':fabric-renderer-api-v1', - ':fabric-renderer-indigo', - ':fabric-rendering-v1', - ':fabric-resource-loader-v1' -]) + testDependencies( + ':fabric-renderer-api-v1', + ':fabric-renderer-indigo', + ':fabric-rendering-v1', + ':fabric-resource-loader-v1' + ) +} loom { accessWidenerPath = file('src/client/resources/fabric-model-loading-api-v1.classtweaker') diff --git a/fabric-networking-api-v1/build.gradle b/fabric-networking-api-v1/build.gradle index e611a82e200..94eb43953f3 100644 --- a/fabric-networking-api-v1/build.gradle +++ b/fabric-networking-api-v1/build.gradle @@ -2,13 +2,17 @@ plugins { id 'fabric-api.module' } -fabricApiModule.moduleDependencies(['fabric-api-base']) +fabricApiModule { + moduleDependencies( + 'fabric-api-base' + ) -fabricApiModule.testDependencies([ - ':fabric-command-api-v2', - ':fabric-lifecycle-events-v1', - ':fabric-key-mapping-api-v1' -]) + testDependencies( + ':fabric-command-api-v2', + ':fabric-lifecycle-events-v1', + ':fabric-key-mapping-api-v1' + ) +} loom { accessWidenerPath = file('src/main/resources/fabric-networking-api-v1.classtweaker') diff --git a/fabric-object-builder-api-v1/build.gradle b/fabric-object-builder-api-v1/build.gradle index 11640631631..1c9660e3f2c 100644 --- a/fabric-object-builder-api-v1/build.gradle +++ b/fabric-object-builder-api-v1/build.gradle @@ -2,17 +2,19 @@ plugins { id 'fabric-api.module' } -fabricApiModule.moduleDependencies([ - 'fabric-api-base', - 'fabric-registry-sync-v0', - 'fabric-resource-loader-v1' -]) +fabricApiModule { + moduleDependencies( + 'fabric-api-base', + 'fabric-registry-sync-v0', + 'fabric-resource-loader-v1' + ) -fabricApiModule.testDependencies([ - ':fabric-command-api-v2', - ':fabric-lifecycle-events-v1', - ':fabric-rendering-v1' -]) + testDependencies( + ':fabric-command-api-v2', + ':fabric-lifecycle-events-v1', + ':fabric-rendering-v1' + ) +} loom { accessWidenerPath = file("src/main/resources/fabric-object-builder-api-v1.classtweaker") diff --git a/fabric-particles-v1/build.gradle b/fabric-particles-v1/build.gradle index 43c8a4d8a27..31fbf309a23 100644 --- a/fabric-particles-v1/build.gradle +++ b/fabric-particles-v1/build.gradle @@ -6,16 +6,18 @@ loom { accessWidenerPath = file("src/main/resources/fabric-particles-v1.classtweaker") } -fabricApiModule.moduleDependencies([ - 'fabric-api-base', - 'fabric-networking-api-v1' -]) +fabricApiModule { + moduleDependencies( + 'fabric-api-base', + 'fabric-networking-api-v1' + ) -fabricApiModule.testDependencies([ + testDependencies( ':fabric-command-api-v2', ':fabric-rendering-v1', ':fabric-resource-loader-v1' -]) + ) +} validateMixinNames { // Loom needs to handle inner mixins better diff --git a/fabric-permission-api-v1/build.gradle b/fabric-permission-api-v1/build.gradle index 16e37287f08..f3946ad727f 100644 --- a/fabric-permission-api-v1/build.gradle +++ b/fabric-permission-api-v1/build.gradle @@ -6,12 +6,14 @@ loom { accessWidenerPath = file('src/main/resources/fabric-permission-api-v1.classtweaker') } -fabricApiModule.moduleDependencies([ - ":fabric-api-base" -]) +fabricApiModule { + moduleDependencies( + ":fabric-api-base" + ) -fabricApiModule.testDependencies([ - ":fabric-command-api-v2", - ":fabric-lifecycle-events-v1", - ":fabric-networking-api-v1" -]) + testDependencies( + ":fabric-command-api-v2", + ":fabric-lifecycle-events-v1", + ":fabric-networking-api-v1" + ) +} diff --git a/fabric-recipe-api-v1/build.gradle b/fabric-recipe-api-v1/build.gradle index d0e3eba8221..7be25c7fa9e 100644 --- a/fabric-recipe-api-v1/build.gradle +++ b/fabric-recipe-api-v1/build.gradle @@ -6,12 +6,14 @@ loom { accessWidenerPath = file('src/main/resources/fabric-recipe-api-v1.classtweaker') } -fabricApiModule.moduleDependencies([ - ':fabric-lifecycle-events-v1', - 'fabric-networking-api-v1', -]) +fabricApiModule { + moduleDependencies( + ':fabric-lifecycle-events-v1', + 'fabric-networking-api-v1', + ) -fabricApiModule.testDependencies([ - ':fabric-lifecycle-events-v1', - ':fabric-registry-sync-v0', -]) + testDependencies( + ':fabric-lifecycle-events-v1', + ':fabric-registry-sync-v0', + ) +} diff --git a/fabric-registry-sync-v0/build.gradle b/fabric-registry-sync-v0/build.gradle index 97eaba607b8..7a7eb3294c9 100644 --- a/fabric-registry-sync-v0/build.gradle +++ b/fabric-registry-sync-v0/build.gradle @@ -6,12 +6,14 @@ loom { accessWidenerPath = file("src/main/resources/fabric-registry-sync-v0.classtweaker") } -fabricApiModule.moduleDependencies([ - 'fabric-api-base', - 'fabric-networking-api-v1' -]) +fabricApiModule { + moduleDependencies( + 'fabric-api-base', + 'fabric-networking-api-v1' + ) -fabricApiModule.testDependencies([ - ':fabric-lifecycle-events-v1', - ':fabric-command-api-v2', -]) + testDependencies( + ':fabric-lifecycle-events-v1', + ':fabric-command-api-v2', + ) +} diff --git a/fabric-renderer-api-v1/build.gradle b/fabric-renderer-api-v1/build.gradle index 8d5be9e8ae2..99acf39880d 100644 --- a/fabric-renderer-api-v1/build.gradle +++ b/fabric-renderer-api-v1/build.gradle @@ -2,22 +2,24 @@ plugins { id 'fabric-api.module' } -fabricApiModule.moduleDependencies([ - ':fabric-api-base', - ':fabric-rendering-v1', - ':fabric-transitive-access-wideners-v1' -]) +fabricApiModule { + moduleDependencies( + ':fabric-api-base', + ':fabric-rendering-v1', + ':fabric-transitive-access-wideners-v1' + ) -fabricApiModule.testDependencies([ - ':fabric-block-api-v1', - ':fabric-block-getter-api-v2', - ':fabric-model-loading-api-v1', - ':fabric-object-builder-api-v1', - ':fabric-particles-v1', - ':fabric-renderer-indigo', - ':fabric-rendering-v1', - ':fabric-resource-loader-v1' -]) + testDependencies( + ':fabric-block-api-v1', + ':fabric-block-getter-api-v2', + ':fabric-model-loading-api-v1', + ':fabric-object-builder-api-v1', + ':fabric-particles-v1', + ':fabric-renderer-indigo', + ':fabric-rendering-v1', + ':fabric-resource-loader-v1' + ) +} loom { accessWidenerPath = file('src/client/resources/fabric-renderer-api-v1.classtweaker') diff --git a/fabric-renderer-indigo/build.gradle b/fabric-renderer-indigo/build.gradle index 00bc09bf25c..3aed92d82f4 100644 --- a/fabric-renderer-indigo/build.gradle +++ b/fabric-renderer-indigo/build.gradle @@ -6,11 +6,13 @@ loom { accessWidenerPath = file("src/client/resources/fabric-renderer-indigo.classtweaker") } -fabricApiModule.moduleDependencies([ - 'fabric-api-base', - 'fabric-renderer-api-v1', - 'fabric-rendering-v1' -]) +fabricApiModule { + moduleDependencies( + 'fabric-api-base', + 'fabric-renderer-api-v1', + 'fabric-rendering-v1' + ) +} sourceSets { mixinConfig { diff --git a/fabric-rendering-fluids-v1/build.gradle b/fabric-rendering-fluids-v1/build.gradle index d7ba5908548..cd865de95e0 100644 --- a/fabric-rendering-fluids-v1/build.gradle +++ b/fabric-rendering-fluids-v1/build.gradle @@ -6,4 +6,8 @@ loom { accessWidenerPath = file('src/main/resources/fabric-rendering-fluids-v1.classtweaker') } -fabricApiModule.moduleDependencies(['fabric-api-base']) +fabricApiModule { + moduleDependencies( + 'fabric-api-base' + ) +} diff --git a/fabric-rendering-v1/build.gradle b/fabric-rendering-v1/build.gradle index f4e11434d41..09428995742 100644 --- a/fabric-rendering-v1/build.gradle +++ b/fabric-rendering-v1/build.gradle @@ -6,15 +6,17 @@ loom { accessWidenerPath = file('src/client/resources/fabric-rendering-v1.classtweaker') } -fabricApiModule.moduleDependencies([ - ':fabric-api-base', - ':fabric-transitive-access-wideners-v1', - ':fabric-lifecycle-events-v1' -]) +fabricApiModule { + moduleDependencies( + ':fabric-api-base', + ':fabric-transitive-access-wideners-v1', + ':fabric-lifecycle-events-v1' + ) -fabricApiModule.testDependencies([ - ':fabric-client-gametest-api-v1', - ':fabric-item-api-v1', - ':fabric-object-builder-api-v1', - ':fabric-screen-api-v1' -]) + testDependencies( + ':fabric-client-gametest-api-v1', + ':fabric-item-api-v1', + ':fabric-object-builder-api-v1', + ':fabric-screen-api-v1' + ) +} diff --git a/fabric-resource-conditions-api-v1/build.gradle b/fabric-resource-conditions-api-v1/build.gradle index 0c93379e7e2..40533c96919 100644 --- a/fabric-resource-conditions-api-v1/build.gradle +++ b/fabric-resource-conditions-api-v1/build.gradle @@ -6,7 +6,9 @@ loom { accessWidenerPath = file("src/main/resources/fabric-resource-conditions-api-v1.classtweaker") } -fabricApiModule.testDependencies([ - ':fabric-lifecycle-events-v1', - ':fabric-resource-loader-v1' -]) +fabricApiModule { + testDependencies( + ':fabric-lifecycle-events-v1', + ':fabric-resource-loader-v1' + ) +} diff --git a/fabric-resource-loader-v1/build.gradle b/fabric-resource-loader-v1/build.gradle index 56dbb071f71..5a946f266ee 100644 --- a/fabric-resource-loader-v1/build.gradle +++ b/fabric-resource-loader-v1/build.gradle @@ -6,14 +6,18 @@ loom { accessWidenerPath = file("src/main/resources/fabric-resource-loader-v1.classtweaker") } -fabricApiModule.moduleDependencies(['fabric-api-base']) - -fabricApiModule.testDependencies([ - ':fabric-lifecycle-events-v1', - ':fabric-api-base', - ':fabric-gametest-api-v1', - ':fabric-resource-loader-v1' -]) +fabricApiModule { + moduleDependencies( + 'fabric-api-base' + ) + + testDependencies( + ':fabric-lifecycle-events-v1', + ':fabric-api-base', + ':fabric-gametest-api-v1', + ':fabric-resource-loader-v1' + ) +} // Setup 3 test mods used for testing resource sorting sourceSets { diff --git a/fabric-screen-api-v1/build.gradle b/fabric-screen-api-v1/build.gradle index 4162d5d89af..05b45fadd08 100644 --- a/fabric-screen-api-v1/build.gradle +++ b/fabric-screen-api-v1/build.gradle @@ -2,4 +2,8 @@ plugins { id 'fabric-api.module' } -fabricApiModule.moduleDependencies(['fabric-api-base']) +fabricApiModule { + moduleDependencies( + 'fabric-api-base' + ) +} diff --git a/fabric-sound-api-v1/build.gradle b/fabric-sound-api-v1/build.gradle index f9a8c81007d..ee4b4f0e0bf 100644 --- a/fabric-sound-api-v1/build.gradle +++ b/fabric-sound-api-v1/build.gradle @@ -6,8 +6,10 @@ loom { accessWidenerPath = file('src/client/resources/fabric-sound-api-v1.classtweaker') } -fabricApiModule.testDependencies([ - ':fabric-api-base', - ':fabric-resource-loader-v1', - ':fabric-command-api-v2' -]) +fabricApiModule { + testDependencies( + ':fabric-api-base', + ':fabric-resource-loader-v1', + ':fabric-command-api-v2' + ) +} diff --git a/fabric-tag-api-v1/build.gradle b/fabric-tag-api-v1/build.gradle index dea3ce7a460..d96fbba500a 100644 --- a/fabric-tag-api-v1/build.gradle +++ b/fabric-tag-api-v1/build.gradle @@ -6,14 +6,16 @@ loom { accessWidenerPath = file('src/main/resources/fabric-tag-api-v1.classtweaker') } -fabricApiModule.moduleDependencies([ - 'fabric-api-base', - 'fabric-resource-loader-v1' -]) +fabricApiModule { + moduleDependencies( + 'fabric-api-base', + 'fabric-resource-loader-v1' + ) -fabricApiModule.testDependencies([ - ':fabric-convention-tags-v2', - ':fabric-client-gametest-api-v1', - ':fabric-lifecycle-events-v1', - ':fabric-resource-loader-v1', -]) + testDependencies( + ':fabric-convention-tags-v2', + ':fabric-client-gametest-api-v1', + ':fabric-lifecycle-events-v1', + ':fabric-resource-loader-v1', + ) +} diff --git a/fabric-transfer-api-v1/build.gradle b/fabric-transfer-api-v1/build.gradle index 30059d6e309..148fefc0816 100644 --- a/fabric-transfer-api-v1/build.gradle +++ b/fabric-transfer-api-v1/build.gradle @@ -2,17 +2,19 @@ plugins { id 'fabric-api.module' } -fabricApiModule.moduleDependencies([ - 'fabric-api-base', - 'fabric-api-lookup-api-v1', - 'fabric-lifecycle-events-v1', - // transitive dependency of API Lookup - 'fabric-rendering-fluids-v1', -]) +fabricApiModule { + moduleDependencies( + 'fabric-api-base', + 'fabric-api-lookup-api-v1', + 'fabric-lifecycle-events-v1', + // transitive dependency of API Lookup + 'fabric-rendering-fluids-v1', + ) -fabricApiModule.testDependencies([ - ':fabric-object-builder-api-v1', - ':fabric-rendering-v1', - ':fabric-resource-loader-v1', - ':fabric-command-api-v2' -]) + testDependencies( + ':fabric-object-builder-api-v1', + ':fabric-rendering-v1', + ':fabric-resource-loader-v1', + ':fabric-command-api-v2' + ) +} diff --git a/fabric-transitive-access-wideners-v1/build.gradle b/fabric-transitive-access-wideners-v1/build.gradle index a4043838aa3..0f1546b6ccd 100644 --- a/fabric-transitive-access-wideners-v1/build.gradle +++ b/fabric-transitive-access-wideners-v1/build.gradle @@ -6,11 +6,12 @@ loom { accessWidenerPath = file('src/main/resources/fabric-transitive-access-wideners-v1.classtweaker') } -fabricApiModule.testDependencies([ - ':fabric-rendering-v1', - ':fabric-object-builder-api-v1' -]) - +fabricApiModule { + testDependencies( + ':fabric-rendering-v1', + ':fabric-object-builder-api-v1' + ) +} import org.objectweb.asm.ClassReader import org.objectweb.asm.ClassVisitor From b9becccfecb0dcb3ce20b61418d64419d8703a0c Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Fri, 5 Jun 2026 18:31:56 +0100 Subject: [PATCH 08/23] split versioning plugins --- .../fabric-api.module-versioning.gradle | 3 ++ .../src/main/groovy/fabric-api.module.gradle | 2 +- .../groovy/fabric-api.root-versioning.gradle | 26 +++++++++++++++++ .../src/main/groovy/fabric-api.root.gradle | 8 ++++- .../main/groovy/fabric-api.versioning.gradle | 29 ------------------- 5 files changed, 37 insertions(+), 31 deletions(-) create mode 100644 buildSrc/src/main/groovy/fabric-api.module-versioning.gradle create mode 100644 buildSrc/src/main/groovy/fabric-api.root-versioning.gradle delete mode 100644 buildSrc/src/main/groovy/fabric-api.versioning.gradle diff --git a/buildSrc/src/main/groovy/fabric-api.module-versioning.gradle b/buildSrc/src/main/groovy/fabric-api.module-versioning.gradle new file mode 100644 index 00000000000..1b52e6cc410 --- /dev/null +++ b/buildSrc/src/main/groovy/fabric-api.module-versioning.gradle @@ -0,0 +1,3 @@ +import net.fabricmc.fabric.impl.build.FabricApiBuildUtils + +version = FabricApiBuildUtils.moduleVersion(project) diff --git a/buildSrc/src/main/groovy/fabric-api.module.gradle b/buildSrc/src/main/groovy/fabric-api.module.gradle index 3e28919c203..d1b9086a153 100644 --- a/buildSrc/src/main/groovy/fabric-api.module.gradle +++ b/buildSrc/src/main/groovy/fabric-api.module.gradle @@ -1,7 +1,7 @@ import net.fabricmc.fabric.impl.build.FabricApiModuleExtension plugins { - id "fabric-api.versioning" + id "fabric-api.module-versioning" id "fabric-api.java" id "fabric-api.lint" id "fabric-api.loom" diff --git a/buildSrc/src/main/groovy/fabric-api.root-versioning.gradle b/buildSrc/src/main/groovy/fabric-api.root-versioning.gradle new file mode 100644 index 00000000000..2c0bf3579cb --- /dev/null +++ b/buildSrc/src/main/groovy/fabric-api.root-versioning.gradle @@ -0,0 +1,26 @@ +import net.fabricmc.fabric.impl.build.BumpVersionTask +import net.fabricmc.fabric.impl.build.FabricApiBuildUtils + +version = FabricApiBuildUtils.rootVersion(project) +logger.lifecycle("Building Fabric: " + version) + +def bumpVersions = tasks.register('bumpVersions', BumpVersionTask) { + gradlePropertiesFile.set(layout.projectDirectory.file("gradle.properties")) +} + +gradle.projectsEvaluated { + def moduleProjects = rootProject.allprojects.findAll { + FabricApiBuildUtils.isFabricModule(it) && it != rootProject + } + + bumpVersions.configure { + moduleNames.set(moduleProjects.collect { it.name }) + moduleVersions.set(moduleProjects.collectEntries { + [(it.name): it.findProperty("${it.name}-version").toString()] + }) + apiDependencies.set(moduleProjects.collectEntries { + def api = it.configurations.findByName("api") + [(it.name): api == null ? "" : api.allDependencies.collect { dependency -> dependency.name }.join(",")] + }) + } +} diff --git a/buildSrc/src/main/groovy/fabric-api.root.gradle b/buildSrc/src/main/groovy/fabric-api.root.gradle index 0800ee0342b..5b8de347703 100644 --- a/buildSrc/src/main/groovy/fabric-api.root.gradle +++ b/buildSrc/src/main/groovy/fabric-api.root.gradle @@ -4,7 +4,13 @@ import org.gradle.api.publish.maven.MavenPublication import org.gradle.external.javadoc.JavadocMemberLevel plugins { - id "fabric-api.module" + id "fabric-api.root-versioning" + id "fabric-api.java" + id "fabric-api.lint" + id "fabric-api.loom" + id "fabric-api.testing" + id "fabric-api.validation" + id "fabric-api.publishing" id "me.modmuss50.mod-publish-plugin" } diff --git a/buildSrc/src/main/groovy/fabric-api.versioning.gradle b/buildSrc/src/main/groovy/fabric-api.versioning.gradle deleted file mode 100644 index bb3cebdca29..00000000000 --- a/buildSrc/src/main/groovy/fabric-api.versioning.gradle +++ /dev/null @@ -1,29 +0,0 @@ -import net.fabricmc.fabric.impl.build.BumpVersionTask -import net.fabricmc.fabric.impl.build.FabricApiBuildUtils - -if (project == rootProject) { - version = FabricApiBuildUtils.rootVersion(project) - logger.lifecycle("Building Fabric: " + version) - def bumpVersions = tasks.register('bumpVersions', BumpVersionTask) { - gradlePropertiesFile.set(layout.projectDirectory.file("gradle.properties")) - } - - gradle.projectsEvaluated { - def moduleProjects = rootProject.allprojects.findAll { - FabricApiBuildUtils.isFabricModule(it) && it != rootProject - } - - bumpVersions.configure { - moduleNames.set(moduleProjects.collect { it.name }) - moduleVersions.set(moduleProjects.collectEntries { - [(it.name): it.findProperty("${it.name}-version").toString()] - }) - apiDependencies.set(moduleProjects.collectEntries { - def api = it.configurations.findByName("api") - [(it.name): api == null ? "" : api.allDependencies.collect { dependency -> dependency.name }.join(",")] - }) - } - } -} else { - version = FabricApiBuildUtils.moduleVersion(project) -} From f363b6aca37d001f93e835b8da89e432ded447dc Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Fri, 5 Jun 2026 18:44:49 +0100 Subject: [PATCH 09/23] split root --- .../groovy/fabric-api.root-publishing.gradle | 171 +++++++++++ .../groovy/fabric-api.root-testing.gradle | 84 ++++++ .../src/main/groovy/fabric-api.root.gradle | 265 +----------------- 3 files changed, 257 insertions(+), 263 deletions(-) create mode 100644 buildSrc/src/main/groovy/fabric-api.root-publishing.gradle create mode 100644 buildSrc/src/main/groovy/fabric-api.root-testing.gradle diff --git a/buildSrc/src/main/groovy/fabric-api.root-publishing.gradle b/buildSrc/src/main/groovy/fabric-api.root-publishing.gradle new file mode 100644 index 00000000000..a89cffc8500 --- /dev/null +++ b/buildSrc/src/main/groovy/fabric-api.root-publishing.gradle @@ -0,0 +1,171 @@ +import groovy.xml.XmlSlurper +import net.fabricmc.fabric.impl.build.FabricApiBuildUtils +import org.gradle.api.publish.maven.MavenPublication +import org.gradle.external.javadoc.JavadocMemberLevel + +plugins { + id "fabric-api.publishing" + id "me.modmuss50.mod-publish-plugin" +} + +def includedModuleProjects = rootProject.allprojects.findAll { + FabricApiBuildUtils.isFabricModule(it) && it != project +} + +javadoc { + enabled = true + + options { + source = "25" + encoding = "UTF-8" + charSet = "UTF-8" + memberLevel = JavadocMemberLevel.PACKAGE + addStringOption("Xdoclint:all,-missing", "-quiet") + addBooleanOption("-syntax-highlight", true) + + tags( + 'apiNote:a:API Note:', + 'implSpec:a:Implementation Requirements:', + 'implNote:a:Implementation Note:' + ) + } + + include("**/api/**") + failOnError = true +} + +tasks.register('javadocJar', Jar) { + dependsOn javadoc + from javadoc.destinationDir + archiveClassifier = "fatjavadoc" +} + +build.dependsOn javadocJar + +publishing { + publications { + mavenJava(MavenPublication) { + artifact(signJar.output) { + builtBy(signJar) + } + + artifact(sourcesJar) { + builtBy sourcesJar + } + + artifact javadocJar + artifact testmodJar + + pom { + FabricApiBuildUtils.addPomMetadataInformation(rootProject, pom) + } + } + } +} + +loom.disableDeprecatedPomGeneration(publishing.publications.mavenJava) + +publishMods { + file = signJar.output + changelog = providers.environmentVariable("CHANGELOG").getOrElse("No changelog provided") + type = project.prerelease == "true" ? BETA : STABLE + displayName = "[${project.minecraft_version}] Fabric API $project.version" + modLoaders.add("fabric") + dryRun = providers.environmentVariable("CURSEFORGE_API_KEY").getOrNull() == null + + curseforge { + accessToken = providers.environmentVariable("CURSEFORGE_API_KEY") + projectId = "306612" + project.curseforge_minecraft_versions.split(",").each { minecraftVersions.add(it.trim()) } + } + + modrinth { + accessToken = providers.environmentVariable("MODRINTH_TOKEN") + projectId = "P7dR8mSH" + minecraftVersions.add(project.minecraft_version) + if (project.modrinth_extra_minecraft_versions) { + project.modrinth_extra_minecraft_versions.split(",").each { minecraftVersions.add(it.trim()) } + } + } + + github { + accessToken = providers.environmentVariable("GITHUB_TOKEN") + repository = providers.environmentVariable("GITHUB_REPOSITORY").getOrElse("FabricMC/dryrun") + commitish = providers.environmentVariable("GITHUB_REF_NAME").getOrElse("dryrun") + } +} + +assemble.dependsOn signJar + +tasks.register('outJar', Copy) { + from signJar.output + into layout.buildDirectory.dir("out") +} + +tasks.register('checkVersion') { + doFirst { + def xml = new URL("https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api/maven-metadata.xml").text + def metadata = new XmlSlurper().parseText(xml) + def versions = metadata.versioning.versions.version*.text() + if (versions.contains(version)) { + throw new RuntimeException("${version} has already been released!") + } + } +} + +tasks.publishMods.dependsOn checkVersion +publish.mustRunAfter checkVersion + +gradle.projectsEvaluated { + for (def moduleProject : includedModuleProjects) { + javadoc.source(moduleProject.sourceSets.main.allJava) + javadoc.source(moduleProject.sourceSets.client.allJava) + } + javadoc.dependsOn(includedModuleProjects.collect { it.tasks.named("classes") }) + javadoc.dependsOn(includedModuleProjects.collect { it.tasks.named("clientClasses") }) + javadoc.classpath = files( + sourceSets.main.compileClasspath, + sourceSets.client.compileClasspath, + includedModuleProjects.collect { it.layout.buildDirectory.dir("classes/java/main") }, + includedModuleProjects.collect { it.layout.buildDirectory.dir("classes/java/client") }, + includedModuleProjects.collect { it.layout.buildDirectory.dir("resources/main") }, + includedModuleProjects.collect { it.layout.buildDirectory.dir("resources/client") } + ) + + publishing.publications.mavenJava { + def dependencies = [] + + for (def moduleProject : includedModuleProjects) { + if (moduleProject.path.startsWith(":deprecated")) { + continue + } + + dependencies.add([ + 'groupId': moduleProject.group, + 'artifactId': moduleProject.name, + 'version': FabricApiBuildUtils.moduleVersion(moduleProject), + 'scope': 'compile' + ]) + } + + def thisGroup = group + def thisVersion = version + + pom.withXml { + def depsNode = asNode().appendNode("dependencies") + for (dep in dependencies) { + def depNode = depsNode.appendNode("dependency") + depNode.appendNode("groupId", dep['groupId']) + depNode.appendNode("artifactId", dep['artifactId']) + depNode.appendNode("version", dep['version']) + depNode.appendNode("scope", dep['scope']) + } + + def depNode = depsNode.appendNode("dependency") + depNode.appendNode("groupId", thisGroup) + depNode.appendNode("artifactId", "fabric-api-deprecated") + depNode.appendNode("version", thisVersion) + depNode.appendNode("scope", "compile") + } + } +} diff --git a/buildSrc/src/main/groovy/fabric-api.root-testing.gradle b/buildSrc/src/main/groovy/fabric-api.root-testing.gradle new file mode 100644 index 00000000000..0dafbdf63f9 --- /dev/null +++ b/buildSrc/src/main/groovy/fabric-api.root-testing.gradle @@ -0,0 +1,84 @@ +import net.fabricmc.fabric.impl.build.FabricApiBuildUtils + +plugins { + id "fabric-api.testing" +} + +def includedModuleProjects = rootProject.allprojects.findAll { + FabricApiBuildUtils.isFabricModule(it) && it != project +} + +loom { + runs { + gametest { + inherit testmodServer + name "Game Test" + vmArg "-Dfabric-api.gametest" + vmArg "-Dfabric-api.gametest.report-file=${project.layout.buildDirectory.file("junit.xml").get().getAsFile()}" + runDir "build/gametest" + } + autoTestServer { + inherit testmodServer + name "Auto Test Server" + vmArg "-Dfabric.autoTest" + } + clientGametest { + inherit testmodClient + name "Client Game Test" + vmArg "-Dfabric.client.gametest" + vmArg "-Dfabric-tag-conventions-v2.missingTagTranslationWarning=fail" + vmArg "-Dfabric-tag-conventions-v1.legacyTagWarning=fail" + } + } +} + +runGametest { + outputs.file project.layout.buildDirectory.file("junit.xml") +} + +gradle.projectsEvaluated { + loom.runs.configureEach { + if (it.name == "gametest" || it.name == "autoTestServer") { + it.source sourceSets.testmod + } + + if (it.name == "clientGametest") { + it.source sourceSets.testmodClient + } + } + + def nestedTestModJars = project.files() + for (def moduleProject : includedModuleProjects) { + if (!(moduleProject.file("src/testmod").exists() || moduleProject.file("src/testmodClient").exists())) { + continue + } + + nestedTestModJars.from(moduleProject.tasks.named("testmodJar")) + } + + tasks.named("runGametest") { + classpath(nestedTestModJars) + } + + tasks.named("runAutoTestServer") { + classpath(nestedTestModJars) + } + + tasks.named("runClientGametest") { + classpath(nestedTestModJars) + } + + for (def moduleProject : includedModuleProjects) { + loom.mods.register(moduleProject.name) { + sourceSet moduleProject.sourceSets.main + sourceSet moduleProject.sourceSets.client + } + + loom.mods.register(moduleProject.name + "-testmod") { + sourceSet moduleProject.sourceSets.testmod + sourceSet moduleProject.sourceSets.testmodClient + } + } + + loom.nestJars(tasks.named("testmodJar"), nestedTestModJars) +} diff --git a/buildSrc/src/main/groovy/fabric-api.root.gradle b/buildSrc/src/main/groovy/fabric-api.root.gradle index 5b8de347703..62df9762c95 100644 --- a/buildSrc/src/main/groovy/fabric-api.root.gradle +++ b/buildSrc/src/main/groovy/fabric-api.root.gradle @@ -1,35 +1,13 @@ -import groovy.xml.XmlSlurper import net.fabricmc.fabric.impl.build.FabricApiBuildUtils -import org.gradle.api.publish.maven.MavenPublication -import org.gradle.external.javadoc.JavadocMemberLevel plugins { id "fabric-api.root-versioning" id "fabric-api.java" id "fabric-api.lint" id "fabric-api.loom" - id "fabric-api.testing" id "fabric-api.validation" - id "fabric-api.publishing" - id "me.modmuss50.mod-publish-plugin" -} - -if (!file("src/client/java").exists()) { - tasks.named("compileClientJava", JavaCompile) { - classpath = files() - } -} - -if (!file("src/testmod/java").exists()) { - tasks.named("compileTestmodJava", JavaCompile) { - classpath = files() - } -} - -if (!file("src/testmodClient/java").exists()) { - tasks.named("compileTestmodClientJava", JavaCompile) { - classpath = files() - } + id "fabric-api.root-testing" + id "fabric-api.root-publishing" } tasks.named("validateModules") { @@ -38,64 +16,8 @@ tasks.named("validateModules") { loom { accessWidenerPath = file("gradle/javadoc.classtweaker") - - runs { - gametest { - inherit testmodServer - name "Game Test" - vmArg "-Dfabric-api.gametest" - vmArg "-Dfabric-api.gametest.report-file=${project.layout.buildDirectory.file("junit.xml").get().getAsFile()}" - runDir "build/gametest" - } - autoTestServer { - inherit testmodServer - name "Auto Test Server" - vmArg "-Dfabric.autoTest" - } - clientGametest { - inherit testmodClient - name "Client Game Test" - vmArg "-Dfabric.client.gametest" - vmArg "-Dfabric-tag-conventions-v2.missingTagTranslationWarning=fail" - vmArg "-Dfabric-tag-conventions-v1.legacyTagWarning=fail" - } - } -} - -runGametest { - outputs.file project.layout.buildDirectory.file("junit.xml") } -javadoc { - enabled = true - - options { - source = "25" - encoding = "UTF-8" - charSet = "UTF-8" - memberLevel = JavadocMemberLevel.PACKAGE - addStringOption("Xdoclint:all,-missing", "-quiet") - addBooleanOption("-syntax-highlight", true) - - tags( - 'apiNote:a:API Note:', - 'implSpec:a:Implementation Requirements:', - 'implNote:a:Implementation Note:' - ) - } - - include("**/api/**") - failOnError = true -} - -tasks.register('javadocJar', Jar) { - dependsOn javadoc - from javadoc.destinationDir - archiveClassifier = "fatjavadoc" -} - -build.dependsOn javadocJar - configurations { nestedJars { transitive = false @@ -116,16 +38,6 @@ dependencies { } } -for (def moduleProject : includedModuleProjects) { - moduleProject.pluginManager.withPlugin("fabric-api.module") { - dependencies { - clientImplementation moduleProject.sourceSets.client.output - testmodImplementation moduleProject.sourceSets.testmod.output - testmodClientImplementation moduleProject.sourceSets.testmodClient.output - } - } -} - loom.nestJars(tasks.named("jar"), configurations.nestedJars) tasks.register("checkNoDuplicateFiles", Zip) { @@ -141,176 +53,3 @@ tasks.register("checkNoDuplicateFiles", Zip) { } check.dependsOn "checkNoDuplicateFiles" - -publishing { - publications { - mavenJava(MavenPublication) { - artifact(signJar.output) { - builtBy(signJar) - } - - artifact(sourcesJar) { - builtBy sourcesJar - } - - artifact javadocJar - artifact testmodJar - - pom { - FabricApiBuildUtils.addPomMetadataInformation(rootProject, pom) - } - } - } -} - -loom.disableDeprecatedPomGeneration(publishing.publications.mavenJava) - -publishMods { - file = signJar.output - changelog = providers.environmentVariable("CHANGELOG").getOrElse("No changelog provided") - type = project.prerelease == "true" ? BETA : STABLE - displayName = "[${project.minecraft_version}] Fabric API $project.version" - modLoaders.add("fabric") - dryRun = providers.environmentVariable("CURSEFORGE_API_KEY").getOrNull() == null - - curseforge { - accessToken = providers.environmentVariable("CURSEFORGE_API_KEY") - projectId = "306612" - project.curseforge_minecraft_versions.split(",").each { minecraftVersions.add(it.trim()) } - } - - modrinth { - accessToken = providers.environmentVariable("MODRINTH_TOKEN") - projectId = "P7dR8mSH" - minecraftVersions.add(project.minecraft_version) - if (project.modrinth_extra_minecraft_versions) { - project.modrinth_extra_minecraft_versions.split(",").each { minecraftVersions.add(it.trim()) } - } - } - - github { - accessToken = providers.environmentVariable("GITHUB_TOKEN") - repository = providers.environmentVariable("GITHUB_REPOSITORY").getOrElse("FabricMC/dryrun") - commitish = providers.environmentVariable("GITHUB_REF_NAME").getOrElse("dryrun") - } -} - -assemble.dependsOn signJar - -tasks.register('outJar', Copy) { - from signJar.output - into layout.buildDirectory.dir("out") -} - -tasks.register('checkVersion') { - doFirst { - def xml = new URL("https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api/maven-metadata.xml").text - def metadata = new XmlSlurper().parseText(xml) - def versions = metadata.versioning.versions.version*.text() - if (versions.contains(version)) { - throw new RuntimeException("${version} has already been released!") - } - } -} - -tasks.publishMods.dependsOn checkVersion -publish.mustRunAfter checkVersion - -gradle.projectsEvaluated { - loom.runs.configureEach { - if (it.name == "gametest" || it.name == "autoTestServer") { - it.source sourceSets.testmod - } - - if (it.name == "clientGametest") { - it.source sourceSets.testmodClient - } - } - - def nestedTestModJars = project.files() - for (def moduleProject : includedModuleProjects) { - if (!(moduleProject.file("src/testmod").exists() || moduleProject.file("src/testmodClient").exists())) { - continue - } - - nestedTestModJars.from(moduleProject.tasks.named("testmodJar")) - } - - tasks.named("runGametest") { - classpath(nestedTestModJars) - } - - tasks.named("runAutoTestServer") { - classpath(nestedTestModJars) - } - - tasks.named("runClientGametest") { - classpath(nestedTestModJars) - } - - for (def moduleProject : includedModuleProjects) { - loom.mods.register(moduleProject.name) { - sourceSet moduleProject.sourceSets.main - sourceSet moduleProject.sourceSets.client - } - - loom.mods.register(moduleProject.name + "-testmod") { - sourceSet moduleProject.sourceSets.testmod - sourceSet moduleProject.sourceSets.testmodClient - } - } - - loom.nestJars(tasks.named("testmodJar"), nestedTestModJars) - - for (def moduleProject : includedModuleProjects) { - javadoc.source(moduleProject.sourceSets.main.allJava) - javadoc.source(moduleProject.sourceSets.client.allJava) - } - javadoc.dependsOn(includedModuleProjects.collect { it.tasks.named("classes") }) - javadoc.dependsOn(includedModuleProjects.collect { it.tasks.named("clientClasses") }) - javadoc.classpath = files( - sourceSets.main.compileClasspath, - sourceSets.client.compileClasspath, - includedModuleProjects.collect { it.layout.buildDirectory.dir("classes/java/main") }, - includedModuleProjects.collect { it.layout.buildDirectory.dir("classes/java/client") }, - includedModuleProjects.collect { it.layout.buildDirectory.dir("resources/main") }, - includedModuleProjects.collect { it.layout.buildDirectory.dir("resources/client") } - ) - - publishing.publications.mavenJava { - def dependencies = [] - - for (def moduleProject : includedModuleProjects) { - if (moduleProject.path.startsWith(":deprecated")) { - continue - } - - dependencies.add([ - 'groupId': moduleProject.group, - 'artifactId': moduleProject.name, - 'version': FabricApiBuildUtils.moduleVersion(moduleProject), - 'scope': 'compile' - ]) - } - - def thisGroup = group - def thisVersion = version - - pom.withXml { - def depsNode = asNode().appendNode("dependencies") - for (dep in dependencies) { - def depNode = depsNode.appendNode("dependency") - depNode.appendNode("groupId", dep['groupId']) - depNode.appendNode("artifactId", dep['artifactId']) - depNode.appendNode("version", dep['version']) - depNode.appendNode("scope", dep['scope']) - } - - def depNode = depsNode.appendNode("dependency") - depNode.appendNode("groupId", thisGroup) - depNode.appendNode("artifactId", "fabric-api-deprecated") - depNode.appendNode("version", thisVersion) - depNode.appendNode("scope", "compile") - } - } -} From 0db58bc40e1f28870dadb905c64f1e22e47a1570 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Fri, 5 Jun 2026 18:48:00 +0100 Subject: [PATCH 10/23] cleanup javadoc --- .../groovy/fabric-api.root-publishing.gradle | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/buildSrc/src/main/groovy/fabric-api.root-publishing.gradle b/buildSrc/src/main/groovy/fabric-api.root-publishing.gradle index a89cffc8500..a287ad22736 100644 --- a/buildSrc/src/main/groovy/fabric-api.root-publishing.gradle +++ b/buildSrc/src/main/groovy/fabric-api.root-publishing.gradle @@ -34,6 +34,13 @@ javadoc { failOnError = true } +for (def moduleProject : includedModuleProjects) { + moduleProject.plugins.withId("fabric-api.module") { + javadoc.source(moduleProject.sourceSets.main.allJava) + javadoc.source(moduleProject.sourceSets.client.allJava) + } +} + tasks.register('javadocJar', Jar) { dependsOn javadoc from javadoc.destinationDir @@ -117,21 +124,6 @@ tasks.publishMods.dependsOn checkVersion publish.mustRunAfter checkVersion gradle.projectsEvaluated { - for (def moduleProject : includedModuleProjects) { - javadoc.source(moduleProject.sourceSets.main.allJava) - javadoc.source(moduleProject.sourceSets.client.allJava) - } - javadoc.dependsOn(includedModuleProjects.collect { it.tasks.named("classes") }) - javadoc.dependsOn(includedModuleProjects.collect { it.tasks.named("clientClasses") }) - javadoc.classpath = files( - sourceSets.main.compileClasspath, - sourceSets.client.compileClasspath, - includedModuleProjects.collect { it.layout.buildDirectory.dir("classes/java/main") }, - includedModuleProjects.collect { it.layout.buildDirectory.dir("classes/java/client") }, - includedModuleProjects.collect { it.layout.buildDirectory.dir("resources/main") }, - includedModuleProjects.collect { it.layout.buildDirectory.dir("resources/client") } - ) - publishing.publications.mavenJava { def dependencies = [] From 50e6a436b0ddf926efa658420b82b5e62327b0af Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Fri, 5 Jun 2026 18:52:04 +0100 Subject: [PATCH 11/23] fabric-api.mixin-config --- .../groovy/fabric-api.mixin-config.gradle | 26 +++++++++++++++++++ fabric-client-gametest-api-v1/build.gradle | 24 +---------------- fabric-renderer-indigo/build.gradle | 24 +---------------- 3 files changed, 28 insertions(+), 46 deletions(-) create mode 100644 buildSrc/src/main/groovy/fabric-api.mixin-config.gradle diff --git a/buildSrc/src/main/groovy/fabric-api.mixin-config.gradle b/buildSrc/src/main/groovy/fabric-api.mixin-config.gradle new file mode 100644 index 00000000000..8e87b0dbffe --- /dev/null +++ b/buildSrc/src/main/groovy/fabric-api.mixin-config.gradle @@ -0,0 +1,26 @@ +plugins { + id "fabric-api.module" +} + +sourceSets { + mixinConfig { + compileClasspath += configurations.loaderLibraries + } + client { + compileClasspath += mixinConfig.output + runtimeClasspath += mixinConfig.output + } +} + +configurations { + clientImplementation.extendsFrom mixinConfigImplementation + clientRuntimeOnly.extendsFrom mixinConfigRuntimeOnly +} + +dependencies { + mixinConfigImplementation "net.fabricmc:fabric-loader:${project.loader_version}" +} + +tasks.named("jar", Jar) { + from sourceSets.mixinConfig.output +} diff --git a/fabric-client-gametest-api-v1/build.gradle b/fabric-client-gametest-api-v1/build.gradle index bc70cd3dec9..9cab8e1393b 100644 --- a/fabric-client-gametest-api-v1/build.gradle +++ b/fabric-client-gametest-api-v1/build.gradle @@ -1,30 +1,8 @@ plugins { id 'fabric-api.module' + id 'fabric-api.mixin-config' } loom { accessWidenerPath = file('src/client/resources/fabric-client-gametest-api-v1.classtweaker') } - -sourceSets { - mixinConfig { - compileClasspath += configurations.loaderLibraries - } - client { - compileClasspath += mixinConfig.output - runtimeClasspath += mixinConfig.output - } -} - -configurations { - clientImplementation.extendsFrom mixinConfigImplementation - clientRuntimeOnly.extendsFrom mixinConfigRuntimeOnly -} - -dependencies { - mixinConfigImplementation "net.fabricmc:fabric-loader:${project.loader_version}" -} - -jar { - from sourceSets.mixinConfig.output -} diff --git a/fabric-renderer-indigo/build.gradle b/fabric-renderer-indigo/build.gradle index 3aed92d82f4..db8bad2fb2c 100644 --- a/fabric-renderer-indigo/build.gradle +++ b/fabric-renderer-indigo/build.gradle @@ -1,5 +1,6 @@ plugins { id 'fabric-api.module' + id 'fabric-api.mixin-config' } loom { @@ -13,26 +14,3 @@ fabricApiModule { 'fabric-rendering-v1' ) } - -sourceSets { - mixinConfig { - compileClasspath += configurations.loaderLibraries - } - client { - compileClasspath += mixinConfig.output - runtimeClasspath += mixinConfig.output - } -} - -configurations { - clientImplementation.extendsFrom mixinConfigImplementation - clientRuntimeOnly.extendsFrom mixinConfigRuntimeOnly -} - -dependencies { - mixinConfigImplementation "net.fabricmc:fabric-loader:${project.loader_version}" -} - -jar { - from sourceSets.mixinConfig.output -} From 2f6c082e9b98093371f3b29c97b22ed2a1ba4833 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Fri, 5 Jun 2026 18:56:04 +0100 Subject: [PATCH 12/23] Remove one plugin --- .../groovy/fabric-api.version-catalog.gradle | 57 ------------------- fabric-api-catalog/build.gradle | 56 +++++++++++++++++- 2 files changed, 55 insertions(+), 58 deletions(-) delete mode 100644 buildSrc/src/main/groovy/fabric-api.version-catalog.gradle diff --git a/buildSrc/src/main/groovy/fabric-api.version-catalog.gradle b/buildSrc/src/main/groovy/fabric-api.version-catalog.gradle deleted file mode 100644 index 6ba82d7bb23..00000000000 --- a/buildSrc/src/main/groovy/fabric-api.version-catalog.gradle +++ /dev/null @@ -1,57 +0,0 @@ -import org.gradle.api.publish.maven.MavenPublication - -plugins { - id "version-catalog" - id "fabric-api.meta-publishing" -} - -version = rootProject.version - -publishing.publications { - register('mavenJava', MavenPublication) { - from components.versionCatalog - } -} - -tasks.withType(GenerateModuleMetadata).configureEach { - enabled = true -} - -tasks.register('configureCatalog') { - doConfigureCatalog() -} - -tasks.named('generateCatalogAsToml') { - dependsOn('configureCatalog') -} - -def doConfigureCatalog() { - for (proj in rootProject.allprojects) { - if (proj == project) { - continue - } - - String catalogName = proj.name - if (catalogName == 'fabric-api-base') { - catalogName = 'base' - } else if (catalogName == 'fabric-api-bom') { - catalogName = 'bom' - } else if (catalogName == 'deprecated') { - catalogName = 'deprecated-fabric-api' - } else if (catalogName == 'fabric-api') { - catalogName = 'fabric-api' - } else { - catalogName = catalogName.substring('fabric-'.length()) - } - - if (proj.parent != null && proj.parent.name == 'deprecated') { - catalogName = 'deprecated-' + catalogName - } - - catalog { - versionCatalog { - library(catalogName, "net.fabricmc.fabric-api:${proj.name}:${proj.version}") - } - } - } -} diff --git a/fabric-api-catalog/build.gradle b/fabric-api-catalog/build.gradle index a8a018adf72..6ba82d7bb23 100644 --- a/fabric-api-catalog/build.gradle +++ b/fabric-api-catalog/build.gradle @@ -1,3 +1,57 @@ +import org.gradle.api.publish.maven.MavenPublication + plugins { - id 'fabric-api.version-catalog' + id "version-catalog" + id "fabric-api.meta-publishing" +} + +version = rootProject.version + +publishing.publications { + register('mavenJava', MavenPublication) { + from components.versionCatalog + } +} + +tasks.withType(GenerateModuleMetadata).configureEach { + enabled = true +} + +tasks.register('configureCatalog') { + doConfigureCatalog() +} + +tasks.named('generateCatalogAsToml') { + dependsOn('configureCatalog') +} + +def doConfigureCatalog() { + for (proj in rootProject.allprojects) { + if (proj == project) { + continue + } + + String catalogName = proj.name + if (catalogName == 'fabric-api-base') { + catalogName = 'base' + } else if (catalogName == 'fabric-api-bom') { + catalogName = 'bom' + } else if (catalogName == 'deprecated') { + catalogName = 'deprecated-fabric-api' + } else if (catalogName == 'fabric-api') { + catalogName = 'fabric-api' + } else { + catalogName = catalogName.substring('fabric-'.length()) + } + + if (proj.parent != null && proj.parent.name == 'deprecated') { + catalogName = 'deprecated-' + catalogName + } + + catalog { + versionCatalog { + library(catalogName, "net.fabricmc.fabric-api:${proj.name}:${proj.version}") + } + } + } } From 027d2da61ad84a220eb826b63cac0f80528cfea4 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Fri, 5 Jun 2026 19:28:19 +0100 Subject: [PATCH 13/23] better --- .../groovy/fabric-api.root-testing.gradle | 76 ++++++++----------- 1 file changed, 30 insertions(+), 46 deletions(-) diff --git a/buildSrc/src/main/groovy/fabric-api.root-testing.gradle b/buildSrc/src/main/groovy/fabric-api.root-testing.gradle index 0dafbdf63f9..96863350d2e 100644 --- a/buildSrc/src/main/groovy/fabric-api.root-testing.gradle +++ b/buildSrc/src/main/groovy/fabric-api.root-testing.gradle @@ -8,6 +8,32 @@ def includedModuleProjects = rootProject.allprojects.findAll { FabricApiBuildUtils.isFabricModule(it) && it != project } +def nestedTestModJars = project.files() + +for (def moduleProject : includedModuleProjects) { + def currentModuleProject = moduleProject + currentModuleProject.afterEvaluate { + if (currentModuleProject.file("src/testmod").exists() || currentModuleProject.file("src/testmodClient").exists()) { + nestedTestModJars.from(currentModuleProject.tasks.named("testmodJar")) + } + + loom.mods.register(currentModuleProject.name) { + sourceSet currentModuleProject.sourceSets.main + sourceSet currentModuleProject.sourceSets.client + } + + loom.mods.register(currentModuleProject.name + "-testmod") { + sourceSet currentModuleProject.sourceSets.testmod + sourceSet currentModuleProject.sourceSets.testmodClient + } + + dependencies { + testmodImplementation currentModuleProject.sourceSets.testmod.output + testmodClientImplementation currentModuleProject.sourceSets.testmodClient.output + } + } +} + loom { runs { gametest { @@ -16,11 +42,13 @@ loom { vmArg "-Dfabric-api.gametest" vmArg "-Dfabric-api.gametest.report-file=${project.layout.buildDirectory.file("junit.xml").get().getAsFile()}" runDir "build/gametest" + source sourceSets.testmod } autoTestServer { inherit testmodServer name "Auto Test Server" vmArg "-Dfabric.autoTest" + source sourceSets.testmod } clientGametest { inherit testmodClient @@ -28,6 +56,7 @@ loom { vmArg "-Dfabric.client.gametest" vmArg "-Dfabric-tag-conventions-v2.missingTagTranslationWarning=fail" vmArg "-Dfabric-tag-conventions-v1.legacyTagWarning=fail" + source sourceSets.testmodClient } } } @@ -36,49 +65,4 @@ runGametest { outputs.file project.layout.buildDirectory.file("junit.xml") } -gradle.projectsEvaluated { - loom.runs.configureEach { - if (it.name == "gametest" || it.name == "autoTestServer") { - it.source sourceSets.testmod - } - - if (it.name == "clientGametest") { - it.source sourceSets.testmodClient - } - } - - def nestedTestModJars = project.files() - for (def moduleProject : includedModuleProjects) { - if (!(moduleProject.file("src/testmod").exists() || moduleProject.file("src/testmodClient").exists())) { - continue - } - - nestedTestModJars.from(moduleProject.tasks.named("testmodJar")) - } - - tasks.named("runGametest") { - classpath(nestedTestModJars) - } - - tasks.named("runAutoTestServer") { - classpath(nestedTestModJars) - } - - tasks.named("runClientGametest") { - classpath(nestedTestModJars) - } - - for (def moduleProject : includedModuleProjects) { - loom.mods.register(moduleProject.name) { - sourceSet moduleProject.sourceSets.main - sourceSet moduleProject.sourceSets.client - } - - loom.mods.register(moduleProject.name + "-testmod") { - sourceSet moduleProject.sourceSets.testmod - sourceSet moduleProject.sourceSets.testmodClient - } - } - - loom.nestJars(tasks.named("testmodJar"), nestedTestModJars) -} +loom.nestJars(tasks.named("testmodJar"), nestedTestModJars) From e073dc4fca539490a4ea4e2175ce097eec770c3d Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Fri, 5 Jun 2026 21:44:39 +0100 Subject: [PATCH 14/23] config cache fix --- buildSrc/src/main/groovy/fabric-api.loom.gradle | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/buildSrc/src/main/groovy/fabric-api.loom.gradle b/buildSrc/src/main/groovy/fabric-api.loom.gradle index 5529d636200..5ee8aa04276 100644 --- a/buildSrc/src/main/groovy/fabric-api.loom.gradle +++ b/buildSrc/src/main/groovy/fabric-api.loom.gradle @@ -18,10 +18,11 @@ dependencies { } tasks.withType(ProcessResources).configureEach { - inputs.property "version", project.version + def modVersion = project.version.toString() + inputs.property "version", modVersion filesMatching("fabric.mod.json") { - expand "version": inputs.properties.version + expand "version": modVersion } } From c4e3290068ddb2d39b80924d14b111384f5ad943 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Sat, 6 Jun 2026 10:01:29 +0100 Subject: [PATCH 15/23] config cache generare resources part 1 --- .../AbstractGenerateClassTweakerTask.java | 164 ++++++++++ fabric-data-generation-api-v1/build.gradle | 178 ++++++----- .../build.gradle | 282 ++++++++---------- 3 files changed, 376 insertions(+), 248 deletions(-) create mode 100644 buildSrc/src/main/java/net/fabricmc/fabric/impl/build/AbstractGenerateClassTweakerTask.java diff --git a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/AbstractGenerateClassTweakerTask.java b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/AbstractGenerateClassTweakerTask.java new file mode 100644 index 00000000000..73a5b240ac3 --- /dev/null +++ b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/AbstractGenerateClassTweakerTask.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.build; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.zip.ZipFile; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.ClassNode; + +import org.gradle.api.DefaultTask; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.tasks.InputFile; +import org.gradle.api.tasks.InputFiles; +import org.gradle.api.tasks.OutputFile; +import org.gradle.api.tasks.PathSensitive; +import org.gradle.api.tasks.PathSensitivity; + +public abstract class AbstractGenerateClassTweakerTask extends DefaultTask { + @InputFiles + @PathSensitive(PathSensitivity.NONE) + public abstract ConfigurableFileCollection getMinecraftJars(); + + @InputFile + @PathSensitive(PathSensitivity.RELATIVE) + public abstract RegularFileProperty getTemplate(); + + @OutputFile + public abstract RegularFileProperty getOutputFile(); + + protected void addHeader(List lines, String format) throws IOException { + addHeader(lines, format, false); + } + + protected void addHeader(List lines, String format, boolean preserveTemplateTrailingNewline) throws IOException { + lines.add(format); + lines.add(""); + lines.add("# DO NOT EDIT BY HAND! This file is generated automatically."); + lines.add("# Edit \"template.classtweaker\" instead then run \"gradlew generateClassTweaker\"."); + lines.add(""); + var template = getTemplate().get().getAsFile().toPath(); + lines.addAll(Files.readAllLines(template, StandardCharsets.UTF_8)); + + if (preserveTemplateTrailingNewline && Files.readString(template, StandardCharsets.UTF_8).endsWith("\n")) { + lines.add(""); + } + } + + protected void writeOutput(List lines) throws IOException { + File outputFile = getOutputFile().get().getAsFile(); + Files.createDirectories(outputFile.toPath().getParent()); + Files.writeString(outputFile.toPath(), String.join("\n", lines) + "\n", StandardCharsets.UTF_8); + } + + protected Map readClasses() throws IOException { + Map classes = new TreeMap<>(); + + for (File input : getMinecraftJars().getFiles()) { + readClasses(input, classes); + } + + return classes; + } + + protected ClassNode readClass(String name) throws IOException { + return readClass(name, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + } + + protected List readPackageClasses(String packageName) throws IOException { + return getMinecraftJars().getFiles().stream() + .flatMap(input -> { + try { + return readPackageClasses(input, packageName).stream(); + } catch (IOException e) { + throw new RuntimeException("Failed to read package " + packageName + " from " + input, e); + } + }) + .toList(); + } + + private static void readClasses(File input, Map classes) throws IOException { + try (ZipFile zip = new ZipFile(input)) { + for (var entries = zip.entries(); entries.hasMoreElements(); ) { + var entry = entries.nextElement(); + + if (!entry.getName().endsWith(".class")) { + continue; + } + + classes.put(entry.getName().replace(".class", ""), readClass(zip, entry.getName(), ClassReader.SKIP_CODE)); + } + } + } + + private ClassNode readClass(String name, int flags) throws IOException { + String path = name + ".class"; + + for (File input : getMinecraftJars().getFiles()) { + try (ZipFile zip = new ZipFile(input)) { + if (zip.getEntry(path) != null) { + return readClass(zip, path, flags); + } + } + } + + throw new IOException("Missing class " + path + " in " + getMinecraftJars().getFiles()); + } + + private static List readPackageClasses(File input, String packageName) throws IOException { + String prefix = packageName + "/"; + + try (ZipFile zip = new ZipFile(input)) { + return zip.stream() + .filter(entry -> !entry.isDirectory()) + .filter(entry -> entry.getName().startsWith(prefix)) + .filter(entry -> entry.getName().endsWith(".class")) + .filter(entry -> entry.getName().indexOf('/', prefix.length()) == -1) + .map(entry -> { + try { + return readClass(zip, entry.getName(), ClassReader.SKIP_CODE); + } catch (IOException e) { + throw new RuntimeException("Failed to read " + entry.getName() + " from " + input, e); + } + }) + .toList(); + } + } + + private static ClassNode readClass(ZipFile zip, String path, int flags) throws IOException { + var entry = zip.getEntry(path); + + if (entry == null) { + throw new IOException("Missing class " + path + " in " + zip.getName()); + } + + try (var inputStream = zip.getInputStream(entry)) { + ClassReader reader = new ClassReader(inputStream); + ClassNode classNode = new ClassNode(); + reader.accept(classNode, flags); + return classNode; + } + } +} diff --git a/fabric-data-generation-api-v1/build.gradle b/fabric-data-generation-api-v1/build.gradle index 1b5dd36b227..7c07272d608 100644 --- a/fabric-data-generation-api-v1/build.gradle +++ b/fabric-data-generation-api-v1/build.gradle @@ -1,3 +1,11 @@ +import net.fabricmc.fabric.impl.build.AbstractGenerateClassTweakerTask + +import org.gradle.api.tasks.TaskAction +import org.objectweb.asm.Opcodes +import org.objectweb.asm.tree.ClassNode + +import java.lang.reflect.Modifier + plugins { id 'fabric-api.module' } @@ -76,145 +84,127 @@ tasks.register('datapackZip', Zip) { build.dependsOn datapackZip -import org.objectweb.asm.ClassReader -import org.objectweb.asm.Opcodes -import org.objectweb.asm.tree.ClassNode - -import java.lang.reflect.Modifier -import java.util.zip.ZipEntry -import java.util.zip.ZipFile +abstract class GenerateDataClassTweakerTask extends AbstractGenerateClassTweakerTask { + @TaskAction + void run() { + def classes = readClasses() + def task = this + List lines = new ArrayList<>() + addHeader(lines, "classTweaker\tv1\tofficial", true) -tasks.register('generateClassTweaker') { - inputs.files(loom.getNamedMinecraftJars()) - - doLast { - // Use parent provider to get the jar before the AWs are applied - def minecraftProvider = loom.namedMinecraftProvider.parentMinecraftProvider - def commonJar = minecraftProvider.commonJar.path.toFile() - def clientJar = minecraftProvider.clientOnlyJar.path.toFile() - def classes = getClasses([commonJar, clientJar]) - - String out = "classTweaker\tv1\tofficial\n" - out += "\n" - out += "# DO NOT EDIT BY HAND! This file is generated automatically.\n" - out += "# Edit \"template.classtweaker\" instead then run \"gradlew generateClassTweaker\".\n" - out += "\n" - out += file("template.classtweaker").text + "\n" - - visitMethods(classes["net/minecraft/data/recipes/RecipeProvider"]) { name, desc, owner -> - if (it.name == "generate") + visitMethods(classes.get("net/minecraft/data/recipes/RecipeProvider")) { method, owner -> + if (method.name == "generate") { return + } - out += "transitive-accessible\tmethod\t${owner}\t${name}\t${desc}\n" + task.addMethod(lines, "transitive-accessible", owner, method) } - visitMethods(classes["net/minecraft/client/data/models/BlockModelGenerators"]) { name, desc, owner -> - if (desc == "()V") - // Skip over methods that dont take any arguments, as they are specific to minecraft. + visitMethods(classes.get("net/minecraft/client/data/models/BlockModelGenerators")) { method, owner -> + if (method.desc == "()V") { return + } - out += "transitive-accessible\tmethod\t${owner}\t${name}\t${desc}\n" + task.addMethod(lines, "transitive-accessible", owner, method) } - visitMethods(classes["net/minecraft/data/loot/BlockLootSubProvider"]) { name, desc, owner -> - out += "transitive-accessible\tmethod\t${owner}\t${name}\t${desc}\n" + visitMethods(classes.get("net/minecraft/data/loot/BlockLootSubProvider")) { method, owner -> + task.addMethod(lines, "transitive-accessible", owner, method) } - visitMethods(classes["net/minecraft/client/data/models/ItemModelGenerators"]) { name, desc, owner -> - out += "transitive-accessible\tmethod\t${owner}\t${name}\t${desc}\n" + visitMethods(classes.get("net/minecraft/client/data/models/ItemModelGenerators")) { method, owner -> + task.addMethod(lines, "transitive-accessible", owner, method) } classes.values().forEach { classNode -> - visitFinalMethods(classNode) { name, desc, owner -> - if (name != "getName" || desc != "()Ljava/lang/String;") { - // Not the method we are after + visitFinalMethods(classNode) { method, owner -> + if (method.name != "getName" || method.desc != "()Ljava/lang/String;") { return } - if (!hasAncestor(classNode, classes, "net/minecraft/data/DataProvider")) { - // Not a descendant of DataProvider + if (!task.hasAncestor(classNode, classes, "net/minecraft/data/DataProvider")) { return } - out += "transitive-extendable\tmethod\t${owner}\t${name}\t${desc}\n" + task.addMethod(lines, "transitive-extendable", owner, method) } } - file("src/main/resources/fabric-data-generation-api-v1.classtweaker").text = out + writeOutput(lines) + } + + void addMethod(List lines, String access, String owner, method) { + lines.add("${access}\tmethod\t${owner}\t${method.name}\t${method.desc}") } -} -static def visitMethods(ClassNode classNode, closure) { - classNode.methods.forEach { - if ((it.access & Opcodes.ACC_SYNTHETIC) != 0 || (it.access & Opcodes.ACC_PUBLIC) != 0) - return + void visitMethods(ClassNode classNode, Closure visitor) { + classNode.methods.forEach { method -> + if ((method.access & Opcodes.ACC_SYNTHETIC) != 0 || (method.access & Opcodes.ACC_PUBLIC) != 0) { + return + } - if (it.name.startsWith("<")) - return + if (method.name.startsWith("<")) { + return + } - closure(it.name, it.desc, classNode.name) + visitor(method, classNode.name) + } } -} -static def visitFinalMethods(ClassNode classNode, closure) { - classNode.methods.forEach { - if (!Modifier.isFinal(it.access)) - return + void visitFinalMethods(ClassNode classNode, Closure visitor) { + classNode.methods.forEach { method -> + if (!Modifier.isFinal(method.access)) { + return + } - if (it.name.startsWith("<")) - return + if (method.name.startsWith("<")) { + return + } - closure(it.name, it.desc, classNode.name) + visitor(method, classNode.name) + } } -} -// Return a map of all class names to classNodes -static def getClasses(List inputs) { - Map classes = new TreeMap<>() + boolean hasAncestor(ClassNode classNode, Map classes, String ancestorName) { + if (classNode.superName == ancestorName) { + return true + } - for (File input : inputs) { - new ZipFile(input).withCloseable { ZipFile zip -> - zip.entries().toList().forEach { ZipEntry entry -> - if (!entry.name.endsWith(".class")) { - return - } + def superClass = classes.get(classNode.superName) - zip.getInputStream(entry).withCloseable { is -> - ClassReader reader = new ClassReader(is) - ClassNode classNode = new ClassNode() - reader.accept(classNode, ClassReader.SKIP_CODE) + if (superClass != null && hasAncestor(superClass, classes, ancestorName)) { + return true + } - classes.put(classNode.name, classNode) - } + for (String interfaceName : classNode.interfaces) { + if (interfaceName == ancestorName) { + return true } - } - } - return classes -} + def ifaceClass = classes.get(interfaceName) -def hasAncestor(ClassNode classNode, Map classes, String ancestorName) { - if (classNode.superName == ancestorName) { - return true - } + if (ifaceClass != null && hasAncestor(ifaceClass, classes, ancestorName)) { + return true + } + } - // Recuse through the super classes - def superClass = classes.get(classNode.superName) - if (superClass != null && hasAncestor(superClass, classes, ancestorName)) { - return true + return false } +} - for (def interfaceName : classNode.interfaces) { - if (interfaceName == ancestorName) { - return true - } +tasks.register('generateClassTweaker', GenerateDataClassTweakerTask) { + template = file("template.classtweaker") + outputFile = file("src/main/resources/fabric-data-generation-api-v1.classtweaker") +} - def ifaceClass = classes.get(interfaceName) - if (ifaceClass != null && hasAncestor(ifaceClass, classes, ancestorName)) { - return true - } +afterEvaluate { + tasks.named('generateClassTweaker', GenerateDataClassTweakerTask) { + // Use parent provider to get the jar before the AWs are applied. + def minecraftProvider = loom.namedMinecraftProvider.parentMinecraftProvider + minecraftJars.from(files(minecraftProvider.commonJar.path.toFile(), minecraftProvider.clientOnlyJar.path.toFile())) } } generateResources.dependsOn generateClassTweaker generateResources.dependsOn runDatagenClient +processResources.dependsOn generateClassTweaker diff --git a/fabric-transitive-access-wideners-v1/build.gradle b/fabric-transitive-access-wideners-v1/build.gradle index 0f1546b6ccd..e72647decda 100644 --- a/fabric-transitive-access-wideners-v1/build.gradle +++ b/fabric-transitive-access-wideners-v1/build.gradle @@ -1,3 +1,11 @@ +import net.fabricmc.fabric.impl.build.AbstractGenerateClassTweakerTask + +import org.gradle.api.tasks.TaskAction +import org.objectweb.asm.ClassVisitor +import org.objectweb.asm.MethodVisitor +import org.objectweb.asm.Opcodes +import org.objectweb.asm.Type + plugins { id 'fabric-api.module' } @@ -13,215 +21,181 @@ fabricApiModule { ) } -import org.objectweb.asm.ClassReader -import org.objectweb.asm.ClassVisitor -import org.objectweb.asm.MethodVisitor -import org.objectweb.asm.Opcodes -import org.objectweb.asm.Type -import org.objectweb.asm.tree.ClassNode - -import java.nio.file.FileSystem -import java.nio.file.FileSystems -import java.nio.file.Files -import java.nio.file.Path +abstract class GenerateTransitiveAccessWidenersClassTweakerTask extends AbstractGenerateClassTweakerTask { + @TaskAction + void run() { + List lines = new ArrayList<>() + addHeader(lines, "accessWidener v2 official") -tasks.register('generateClassTweaker') { - doLast { - List lines = new ArrayList<>(); - lines.add("accessWidener v2 official") + generateBlockConstructors(lines) lines.add("") - lines.add("# DO NOT EDIT BY HAND! This file is generated automatically.") - lines.add("# Edit \"template.classtweaker\" instead then run \"gradlew generateClassTweaker\".") + generateCreatorEntityTrackedDataMethods(lines) lines.add("") - lines.addAll(file("template.classtweaker").text.lines().toList()) - - Path commonJar = loom.namedMinecraftProvider.parentMinecraftProvider.commonJar.path - - FileSystems.newFileSystem(URI.create("jar:${commonJar.toUri()}"), [create: false]).withCloseable { fs -> - generateBlockConstructors(lines, fs) - lines.add("") - generateCreatorEntityTrackedDataMethods(lines, fs) - lines.add("") - generateEnchantmentMethods(lines, fs) - lines.add("") - generateNoiseRouterDataFieldsAndMethods(lines, fs) - lines.add("") - } - - Path clientJar = loom.namedMinecraftProvider.parentMinecraftProvider.clientOnlyJar.path - - FileSystems.newFileSystem(URI.create("jar:${clientJar.toUri()}"), [create: false]).withCloseable { fs -> - generateRenderPipelinesFields(lines, fs) - } - - file('src/main/resources/fabric-transitive-access-wideners-v1.classtweaker').text = String.join('\n', lines) + '\n' + generateEnchantmentMethods(lines) + lines.add("") + generateNoiseRouterDataFieldsAndMethods(lines) + lines.add("") + generateRenderPipelinesFields(lines) validateAccessWidener(lines) + writeOutput(lines) } -} -def generateBlockConstructors(List lines, FileSystem fs) { - lines.add("# Constructors of non-abstract block classes") - Files.list(fs.getPath("net/minecraft/world/level/block/")) - .filter { Files.isRegularFile(it) && it.toString().endsWith(".class") } - .map { loadClass(it) } - .sorted(Comparator.comparing { it.name }) - .filter { (it.access & Opcodes.ACC_ABSTRACT) == 0 } - .forEach { node -> - for (def method : node.methods) { - // Checklist for finding block constructors as of 1.19.3: - // - class directly in net.minecraft.block (excluding subpackages) - // - method name == (by definition) - // - contains an AbstractBlock$Settings parameter - // - only taking into account non-abstract classes and non-public constructors - - // Block constructor... - if (method.name == "" && Type.getArgumentTypes(method.desc).any { it.internalName == 'net/minecraft/world/level/block/state/BlockBehaviour$Properties' }) { - // ...and non-public - if ((method.access & Opcodes.ACC_PUBLIC) == 0) { - lines.add("transitive-accessible method $node.name $method.desc") + private void generateBlockConstructors(List lines) { + lines.add("# Constructors of non-abstract block classes") + + readPackageClasses("net/minecraft/world/level/block") + .toSorted { it.name } + .findAll { (it.access & Opcodes.ACC_ABSTRACT) == 0 } + .forEach { node -> + for (def method : node.methods) { + def takesBlockProperties = Type.getArgumentTypes(method.desc).any { + it.internalName == "net/minecraft/world/level/block/state/BlockBehaviour\$Properties" + } + + if (method.name == "" && takesBlockProperties && (method.access & Opcodes.ACC_PUBLIC) == 0) { + lines.add("transitive-accessible method ${node.name} ${method.desc}") } } } - } -} - -def generateRenderPipelinesFields(List lines, FileSystem fs) { - lines.add("# private fields of RenderPipelines") + } - def node = loadClass(fs.getPath("net/minecraft/client/renderer/RenderPipelines.class")) + private void generateRenderPipelinesFields(List lines) { + lines.add("# private fields of RenderPipelines") + def node = readClass("net/minecraft/client/renderer/RenderPipelines") - for (def field : node.fields) { - // All private fields of RenderPipelines of type RenderPipeline.Snippet - if ((field.access & Opcodes.ACC_PRIVATE) != 0 && field.desc == "Lcom/mojang/blaze3d/pipeline/RenderPipeline\$Snippet;") { - lines.add("transitive-accessible field $node.name ${field.name} ${field.desc}") + for (def field : node.fields) { + if ((field.access & Opcodes.ACC_PRIVATE) != 0 && field.desc == "Lcom/mojang/blaze3d/pipeline/RenderPipeline\$Snippet;") { + lines.add("transitive-accessible field ${node.name} ${field.name} ${field.desc}") + } } - } - for (def method : node.methods) { - if ((method.access & Opcodes.ACC_PRIVATE) != 0 && (method.access & Opcodes.ACC_STATIC) != 0) { - lines.add("transitive-accessible method $node.name $method.name $method.desc") + for (def method : node.methods) { + if ((method.access & Opcodes.ACC_PRIVATE) != 0 && (method.access & Opcodes.ACC_STATIC) != 0) { + lines.add("transitive-accessible method ${node.name} ${method.name} ${method.desc}") + } } } -} -def generateNoiseRouterDataFieldsAndMethods(List lines, FileSystem fs) { - lines.add("# private fields of NoiseRouterData") + private void generateNoiseRouterDataFieldsAndMethods(List lines) { + lines.add("# private fields of NoiseRouterData") + def node = readClass("net/minecraft/world/level/levelgen/NoiseRouterData") - def node = loadClass(fs.getPath("net/minecraft/world/level/levelgen/NoiseRouterData.class")) - - for (def field : node.fields) { - // Every field can be useful - if ((field.access & Opcodes.ACC_PRIVATE) != 0) { - lines.add("transitive-accessible field $node.name $field.name $field.desc") + for (def field : node.fields) { + if ((field.access & Opcodes.ACC_PRIVATE) != 0) { + lines.add("transitive-accessible field ${node.name} ${field.name} ${field.desc}") + } } - } - lines.add("# private and protected methods of NoiseRouterData") + lines.add("# private and protected methods of NoiseRouterData") - for (def method : node.methods) { - // Every method can be useful, but using the vanilla namespace is not recommended - if ((method.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED)) && !method.name.startsWith("lambda") && method.name != "createKey") { - lines.add("transitive-accessible method $node.name $method.name $method.desc") + for (def method : node.methods) { + if ((method.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED)) != 0 && !method.name.startsWith("lambda") && method.name != "createKey") { + lines.add("transitive-accessible method ${node.name} ${method.name} ${method.desc}") + } } } -} -def generateTrackedDataFields(String className, List lines, FileSystem fs, String... extraMethods) { - // using a set to prevent duplicates from multiple dataTracker references in a single method - // linked to preserve order and improve generated access widener readability - Set collectedWideners = new LinkedHashSet<>() + private void generateTrackedDataFields(String className, List lines, String... extraMethods) { + Set collectedWideners = new LinkedHashSet<>() - loadClass(fs.getPath("${className}.class")).accept( - new ClassVisitor(Opcodes.ASM9) { + readClass(className).accept(new ClassVisitor(Opcodes.ASM9) { @Override MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { boolean isExtra = extraMethods.contains(name) - if (!isExtra) { - // check for desired methods - if (!name.startsWith("get") && !name.startsWith("set")) { - return null - } - // check methods as genuine basic getter/setters - int parameterCount = Type.getArgumentCount(descriptor) - - if (name.startsWith("get") && parameterCount != 0) { - return null - } - - if (name.startsWith("set") && parameterCount != 1) { - return null - } - } else { - println name + if (!isExtra && !isTrackedDataAccessor(name, descriptor)) { + return null } return new MethodVisitor(Opcodes.ASM9) { @Override void visitFieldInsn(int opcode, String owner, String fieldName, String fieldDescriptor) { - // check references its dataTracker field - if (isExtra || (fieldName == "entityData" && opcode == Opcodes.GETFIELD)) { - collectedWideners.add("transitive-accessible method $className $name $descriptor") + if (isExtra || fieldName == "entityData" && opcode == Opcodes.GETFIELD) { + collectedWideners.add("transitive-accessible method ${className} ${name} ${descriptor}") } } } } - } - ) - - lines.addAll(collectedWideners) -} + }) -def generateCreatorEntityTrackedDataMethods(List lines, FileSystem fs) { - lines.add("# Private tracked data related methods of DisplayEntity (plus its subclasses) and InteractionEntity") + lines.addAll(collectedWideners) + } - generateTrackedDataFields("net/minecraft/world/entity/Display", lines, fs, "getTransformation") - generateTrackedDataFields("net/minecraft/world/entity/Display\$ItemDisplay", lines, fs) - generateTrackedDataFields("net/minecraft/world/entity/Display\$BlockDisplay", lines, fs) - generateTrackedDataFields("net/minecraft/world/entity/Display\$TextDisplay", lines, fs) - generateTrackedDataFields("net/minecraft/world/entity/Interaction", lines, fs, "shouldRespond") -} + private void generateCreatorEntityTrackedDataMethods(List lines) { + lines.add("# Private tracked data related methods of DisplayEntity (plus its subclasses) and InteractionEntity") + generateTrackedDataFields("net/minecraft/world/entity/Display", lines, "getTransformation") + generateTrackedDataFields("net/minecraft/world/entity/Display\$ItemDisplay", lines) + generateTrackedDataFields("net/minecraft/world/entity/Display\$BlockDisplay", lines) + generateTrackedDataFields("net/minecraft/world/entity/Display\$TextDisplay", lines) + generateTrackedDataFields("net/minecraft/world/entity/Interaction", lines, "shouldRespond") + } -def generateEnchantmentMethods(List lines, FileSystem fs) { - lines.add("# Private methods of Enchantment and EnchantmentHelper") + private void generateEnchantmentMethods(List lines) { + lines.add("# Private methods of Enchantment and EnchantmentHelper") - for (def node : [ loadClass(fs.getPath("net/minecraft/world/item/enchantment/EnchantmentHelper.class")), loadClass(fs.getPath("net/minecraft/world/item/enchantment/Enchantment.class")) ]) { - for (def method : node.methods) { - // All private inner methods of EnchantmentHelper - if ((method.access & Opcodes.ACC_PRIVATE) != 0 && !method.name.startsWith("lambda\$")) { - lines.add("transitive-accessible method $node.name $method.name $method.desc") + for (def node : [ + readClass("net/minecraft/world/item/enchantment/EnchantmentHelper"), + readClass("net/minecraft/world/item/enchantment/Enchantment") + ]) { + for (def method : node.methods) { + if ((method.access & Opcodes.ACC_PRIVATE) != 0 && !method.name.startsWith("lambda\$")) { + lines.add("transitive-accessible method ${node.name} ${method.name} ${method.desc}") + } } } + + lines.add("transitive-accessible class net/minecraft/world/item/enchantment/EnchantmentHelper\$EnchantmentVisitor") + lines.add("transitive-accessible class net/minecraft/world/item/enchantment/EnchantmentHelper\$EnchantmentInSlotVisitor") + lines.add("transitive-accessible class net/minecraft/world/item/enchantment/Enchantment\$GenericAction") + lines.add("transitive-accessible class net/minecraft/world/item/enchantment/Enchantment\$FloatAction") } - lines.add('transitive-accessible class net/minecraft/world/item/enchantment/EnchantmentHelper$EnchantmentVisitor') - lines.add('transitive-accessible class net/minecraft/world/item/enchantment/EnchantmentHelper$EnchantmentInSlotVisitor') - lines.add('transitive-accessible class net/minecraft/world/item/enchantment/Enchantment$GenericAction') - lines.add('transitive-accessible class net/minecraft/world/item/enchantment/Enchantment$FloatAction') -} -ClassNode loadClass(Path path) { - def node = new ClassNode() + private static boolean isTrackedDataAccessor(String name, String descriptor) { + int parameterCount = Type.getArgumentCount(descriptor) + + if (name.startsWith("get")) { + return parameterCount == 0 + } + + if (name.startsWith("set")) { + return parameterCount == 1 + } - Files.newInputStream(path).withCloseable { is -> - new ClassReader(is).accept(node, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES) + return false } - return node -} + private static void validateAccessWidener(List lines) { + List exceptions = new ArrayList<>() -def validateAccessWidener(List lines) { - List exceptions = new ArrayList<>() + for (int i = 0; i < lines.size(); i++) { + String line = lines.get(i) + + if (line.isBlank() || line.startsWith("#") || line.startsWith("transitive-") || line.startsWith("accessWidener")) { + continue + } - for (int i = 0; i < lines.size(); i++) { - String line = lines.get(i) - if (line.isBlank() || line.startsWith("#") || line.startsWith("transitive-") || line.startsWith("accessWidener")) continue exceptions.add(String.valueOf(i + 1)) + } + + if (!exceptions.isEmpty()) { + throw new RuntimeException("\"fabric-transitive-access-wideners-v1.classtweaker\" contains non-transitive access modifiers at lines: [${String.join(", ", exceptions)}]") + } } +} + +tasks.register('generateClassTweaker', GenerateTransitiveAccessWidenersClassTweakerTask) { + template = file("template.classtweaker") + outputFile = file("src/main/resources/fabric-transitive-access-wideners-v1.classtweaker") +} - if (exceptions.size() > 0) { - throw new InvalidUserDataException("\"fabric-transitive-access-wideners-v1.classtweaker\" contains non-transitive access modifiers at lines: [" + String.join(", ", exceptions) + "]") +afterEvaluate { + tasks.named('generateClassTweaker', GenerateTransitiveAccessWidenersClassTweakerTask) { + // Use parent provider to get the jar before the AWs are applied. + def minecraftProvider = loom.namedMinecraftProvider.parentMinecraftProvider + minecraftJars.from(files(minecraftProvider.commonJar.path.toFile(), minecraftProvider.clientOnlyJar.path.toFile())) } } generateResources.dependsOn generateClassTweaker +processResources.dependsOn generateClassTweaker From 90845efa61f0c31e08be0c9236c726fb79466cd7 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Sat, 6 Jun 2026 10:04:18 +0100 Subject: [PATCH 16/23] config cache generare resources part 2 --- .../impl/build/AbstractGenerateClassTweakerTask.java | 12 +++++++++--- fabric-data-generation-api-v1/build.gradle | 8 -------- fabric-transitive-access-wideners-v1/build.gradle | 8 -------- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/AbstractGenerateClassTweakerTask.java b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/AbstractGenerateClassTweakerTask.java index 73a5b240ac3..ac60fda9b76 100644 --- a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/AbstractGenerateClassTweakerTask.java +++ b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/AbstractGenerateClassTweakerTask.java @@ -25,9 +25,6 @@ import java.util.TreeMap; import java.util.zip.ZipFile; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.tree.ClassNode; - import org.gradle.api.DefaultTask; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.RegularFileProperty; @@ -36,6 +33,11 @@ import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.PathSensitive; import org.gradle.api.tasks.PathSensitivity; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.ClassNode; + +import net.fabricmc.loom.LoomGradleExtension; +import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; public abstract class AbstractGenerateClassTweakerTask extends DefaultTask { @InputFiles @@ -49,6 +51,10 @@ public abstract class AbstractGenerateClassTweakerTask extends DefaultTask { @OutputFile public abstract RegularFileProperty getOutputFile(); + public AbstractGenerateClassTweakerTask() { + getMinecraftJars().from(getProject().provider(() -> LoomGradleExtension.get(getProject()).getMinecraftJars(MappingsNamespace.OFFICIAL))); + } + protected void addHeader(List lines, String format) throws IOException { addHeader(lines, format, false); } diff --git a/fabric-data-generation-api-v1/build.gradle b/fabric-data-generation-api-v1/build.gradle index 7c07272d608..5e3d744006d 100644 --- a/fabric-data-generation-api-v1/build.gradle +++ b/fabric-data-generation-api-v1/build.gradle @@ -197,14 +197,6 @@ tasks.register('generateClassTweaker', GenerateDataClassTweakerTask) { outputFile = file("src/main/resources/fabric-data-generation-api-v1.classtweaker") } -afterEvaluate { - tasks.named('generateClassTweaker', GenerateDataClassTweakerTask) { - // Use parent provider to get the jar before the AWs are applied. - def minecraftProvider = loom.namedMinecraftProvider.parentMinecraftProvider - minecraftJars.from(files(minecraftProvider.commonJar.path.toFile(), minecraftProvider.clientOnlyJar.path.toFile())) - } -} - generateResources.dependsOn generateClassTweaker generateResources.dependsOn runDatagenClient processResources.dependsOn generateClassTweaker diff --git a/fabric-transitive-access-wideners-v1/build.gradle b/fabric-transitive-access-wideners-v1/build.gradle index e72647decda..a09f918fb1d 100644 --- a/fabric-transitive-access-wideners-v1/build.gradle +++ b/fabric-transitive-access-wideners-v1/build.gradle @@ -189,13 +189,5 @@ tasks.register('generateClassTweaker', GenerateTransitiveAccessWidenersClassTwea outputFile = file("src/main/resources/fabric-transitive-access-wideners-v1.classtweaker") } -afterEvaluate { - tasks.named('generateClassTweaker', GenerateTransitiveAccessWidenersClassTweakerTask) { - // Use parent provider to get the jar before the AWs are applied. - def minecraftProvider = loom.namedMinecraftProvider.parentMinecraftProvider - minecraftJars.from(files(minecraftProvider.commonJar.path.toFile(), minecraftProvider.clientOnlyJar.path.toFile())) - } -} - generateResources.dependsOn generateClassTweaker processResources.dependsOn generateClassTweaker From 8d251cf87f7efc40cec795eaf1d22a123f6b037f Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Sat, 6 Jun 2026 10:05:34 +0100 Subject: [PATCH 17/23] config cache generare resources part 3 --- fabric-data-generation-api-v1/build.gradle | 2 +- fabric-transitive-access-wideners-v1/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fabric-data-generation-api-v1/build.gradle b/fabric-data-generation-api-v1/build.gradle index 5e3d744006d..371f883c403 100644 --- a/fabric-data-generation-api-v1/build.gradle +++ b/fabric-data-generation-api-v1/build.gradle @@ -199,4 +199,4 @@ tasks.register('generateClassTweaker', GenerateDataClassTweakerTask) { generateResources.dependsOn generateClassTweaker generateResources.dependsOn runDatagenClient -processResources.dependsOn generateClassTweaker +processResources.mustRunAfter generateClassTweaker diff --git a/fabric-transitive-access-wideners-v1/build.gradle b/fabric-transitive-access-wideners-v1/build.gradle index a09f918fb1d..bda81c18975 100644 --- a/fabric-transitive-access-wideners-v1/build.gradle +++ b/fabric-transitive-access-wideners-v1/build.gradle @@ -190,4 +190,4 @@ tasks.register('generateClassTweaker', GenerateTransitiveAccessWidenersClassTwea } generateResources.dependsOn generateClassTweaker -processResources.dependsOn generateClassTweaker +processResources.mustRunAfter generateClassTweaker From 553d25354cc6388dec8a75adf7321745fff391fb Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Sat, 6 Jun 2026 10:22:10 +0100 Subject: [PATCH 18/23] Use versions.toml file --- build.gradle | 6 +++--- buildSrc/build.gradle | 6 +++--- buildSrc/settings.gradle | 7 +++++++ .../src/main/groovy/fabric-api.lint.gradle | 4 +++- .../src/main/groovy/fabric-api.loom.gradle | 3 ++- .../groovy/fabric-api.mixin-config.gradle | 4 +++- .../src/main/groovy/fabric-api.testing.gradle | 5 +++-- .../impl/build/FabricApiBuildUtils.java | 19 ++++++++++++++++++ .../fabric/impl/build/ValidateModuleTask.java | 2 +- gradle.properties | 2 -- gradle/libs.versions.toml | 20 +++++++++++++++++++ 11 files changed, 64 insertions(+), 14 deletions(-) create mode 100644 buildSrc/settings.gradle create mode 100644 gradle/libs.versions.toml diff --git a/build.gradle b/build.gradle index b6dec108b16..b3a59972c50 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { - id "com.diffplug.spotless" version "8.5.1" apply false - id "me.modmuss50.remotesign" version "0.5.0" apply false - id "me.modmuss50.mod-publish-plugin" version "2.0.0-beta.1" apply false + alias(libs.plugins.spotless) apply false + alias(libs.plugins.remote.sign) apply false + alias(libs.plugins.mod.publish) apply false id "fabric-api.root" } diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 4c37c839bbb..572cde3454f 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -1,7 +1,7 @@ plugins { id 'groovy-gradle-plugin' id 'checkstyle' - id "com.diffplug.spotless" version "6.20.0" + alias(libs.plugins.spotless) } repositories { @@ -14,12 +14,12 @@ repositories { } dependencies { - implementation "net.fabricmc:fabric-loom:1.17.0-alpha.19" + implementation libs.fabric.loom } checkstyle { configFile = file("../checkstyle.xml") - toolVersion = "10.20.2" + toolVersion = libs.versions.checkstyle.get() } spotless { diff --git a/buildSrc/settings.gradle b/buildSrc/settings.gradle new file mode 100644 index 00000000000..0aba7326a42 --- /dev/null +++ b/buildSrc/settings.gradle @@ -0,0 +1,7 @@ +dependencyResolutionManagement { + versionCatalogs { + libs { + from(files("../gradle/libs.versions.toml")) + } + } +} diff --git a/buildSrc/src/main/groovy/fabric-api.lint.gradle b/buildSrc/src/main/groovy/fabric-api.lint.gradle index 89845c05c3f..2fd58410f58 100644 --- a/buildSrc/src/main/groovy/fabric-api.lint.gradle +++ b/buildSrc/src/main/groovy/fabric-api.lint.gradle @@ -1,3 +1,5 @@ +import net.fabricmc.fabric.impl.build.FabricApiBuildUtils + plugins { id "checkstyle" id "com.diffplug.spotless" @@ -5,7 +7,7 @@ plugins { checkstyle { configFile = rootProject.file("checkstyle.xml") - toolVersion = "13.3.0" + toolVersion = FabricApiBuildUtils.version(project, "checkstyle") } spotless { diff --git a/buildSrc/src/main/groovy/fabric-api.loom.gradle b/buildSrc/src/main/groovy/fabric-api.loom.gradle index 5ee8aa04276..b35bc309ed6 100644 --- a/buildSrc/src/main/groovy/fabric-api.loom.gradle +++ b/buildSrc/src/main/groovy/fabric-api.loom.gradle @@ -1,4 +1,5 @@ import net.fabricmc.loom.task.tool.ModEnigmaTask +import net.fabricmc.fabric.impl.build.FabricApiBuildUtils plugins { id "net.fabricmc.fabric-loom" @@ -14,7 +15,7 @@ loom { dependencies { minecraft "com.mojang:minecraft:$rootProject.minecraft_version" - api "net.fabricmc:fabric-loader:${project.loader_version}" + api FabricApiBuildUtils.library(project, "fabric-loader") } tasks.withType(ProcessResources).configureEach { diff --git a/buildSrc/src/main/groovy/fabric-api.mixin-config.gradle b/buildSrc/src/main/groovy/fabric-api.mixin-config.gradle index 8e87b0dbffe..fc0f446e969 100644 --- a/buildSrc/src/main/groovy/fabric-api.mixin-config.gradle +++ b/buildSrc/src/main/groovy/fabric-api.mixin-config.gradle @@ -1,3 +1,5 @@ +import net.fabricmc.fabric.impl.build.FabricApiBuildUtils + plugins { id "fabric-api.module" } @@ -18,7 +20,7 @@ configurations { } dependencies { - mixinConfigImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + mixinConfigImplementation FabricApiBuildUtils.library(project, "fabric-loader") } tasks.named("jar", Jar) { diff --git a/buildSrc/src/main/groovy/fabric-api.testing.gradle b/buildSrc/src/main/groovy/fabric-api.testing.gradle index c620c42a446..9faabbec969 100644 --- a/buildSrc/src/main/groovy/fabric-api.testing.gradle +++ b/buildSrc/src/main/groovy/fabric-api.testing.gradle @@ -1,4 +1,5 @@ import net.fabricmc.loom.task.ValidateMixinNameTask +import net.fabricmc.fabric.impl.build.FabricApiBuildUtils def debugArgs = [ "-enableassertions", @@ -59,9 +60,9 @@ dependencies { testmodClientImplementation sourceSets.client.output testmodClientImplementation sourceSets.testmod.output - testImplementation "net.fabricmc:fabric-loader-junit:${project.loader_version}" + testImplementation FabricApiBuildUtils.library(project, "fabric-loader-junit") testImplementation sourceSets.testmodClient.output - testImplementation 'org.mockito:mockito-core:5.23.0' + testImplementation FabricApiBuildUtils.library(project, "mockito-core") } test { diff --git a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiBuildUtils.java b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiBuildUtils.java index b0c373db4ea..ecbfbb13db9 100644 --- a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiBuildUtils.java +++ b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiBuildUtils.java @@ -31,7 +31,11 @@ import groovy.json.JsonSlurper; import groovy.util.Node; import org.gradle.api.Project; +import org.gradle.api.artifacts.MinimalExternalModuleDependency; +import org.gradle.api.artifacts.VersionCatalog; +import org.gradle.api.artifacts.VersionCatalogsExtension; import org.gradle.api.artifacts.dsl.RepositoryHandler; +import org.gradle.api.provider.Provider; import org.gradle.api.publish.maven.MavenPom; public final class FabricApiBuildUtils { @@ -91,6 +95,21 @@ public static String moduleVersion(Project project) { return version + "+" + hashProvider.get().substring(0, 8) + sha256Hex(project.getRootProject().property("minecraft_version").toString()).substring(0, 2); } + public static String version(Project project, String alias) { + return libs(project).findVersion(alias) + .orElseThrow(() -> new IllegalStateException("Missing version catalog entry: " + alias)) + .getRequiredVersion(); + } + + public static Provider library(Project project, String alias) { + return libs(project).findLibrary(alias) + .orElseThrow(() -> new IllegalStateException("Missing version catalog entry: " + alias)); + } + + private static VersionCatalog libs(Project project) { + return project.getExtensions().getByType(VersionCatalogsExtension.class).named("libs"); + } + public static void setupRepositories(Project project, RepositoryHandler repositories) { if (project.getProviders().environmentVariable("MAVEN_URL").isPresent()) { repositories.maven(repository -> { diff --git a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/ValidateModuleTask.java b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/ValidateModuleTask.java index c2b89216420..bfdcd63df86 100644 --- a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/ValidateModuleTask.java +++ b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/ValidateModuleTask.java @@ -53,7 +53,7 @@ public ValidateModuleTask() { getFmj().set(file); getProjectName().set(getProject().getName()); getProjectPath().set(getProject().getPath()); - getLoaderVersion().set(getProject().property("loader_version").toString()); + getLoaderVersion().set(FabricApiBuildUtils.version(getProject(), "fabric-loader")); } @TaskAction diff --git a/gradle.properties b/gradle.properties index 180612a7511..1097eebbd49 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,8 +4,6 @@ org.gradle.configuration-cache=true version=0.150.3 minecraft_version=26.2-pre-4 -loader_version=0.18.4 -installer_version=1.0.1 prerelease=true curseforge_minecraft_versions=26.1-snapshot diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 00000000000..c16ed156744 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,20 @@ +[versions] +fabric-loader = "0.18.4" +fabric-installer = "1.0.1" +fabric-loom = "1.17.0-alpha.19" +spotless = "8.6.0" +remote-sign = "0.5.0" +mod-publish = "2.0.0-beta.1" +checkstyle = "13.5.0" +mockito = "5.23.0" + +[libraries] +fabric-loader = { module = "net.fabricmc:fabric-loader", version.ref = "fabric-loader" } +fabric-loader-junit = { module = "net.fabricmc:fabric-loader-junit", version.ref = "fabric-loader" } +fabric-loom = { module = "net.fabricmc:fabric-loom", version.ref = "fabric-loom" } +mockito-core = { module = "org.mockito:mockito-core", version.ref = "mockito" } + +[plugins] +spotless = { id = "com.diffplug.spotless", version.ref = "spotless" } +remote-sign = { id = "me.modmuss50.remotesign", version.ref = "remote-sign" } +mod-publish = { id = "me.modmuss50.mod-publish-plugin", version.ref = "mod-publish" } From 53f2b402a728feb79c1f17f769d9a9d28355a318 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Sat, 6 Jun 2026 10:31:44 +0100 Subject: [PATCH 19/23] Update MPP --- buildSrc/src/main/groovy/fabric-api.root-publishing.gradle | 2 ++ gradle/libs.versions.toml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/buildSrc/src/main/groovy/fabric-api.root-publishing.gradle b/buildSrc/src/main/groovy/fabric-api.root-publishing.gradle index a287ad22736..702c4f0a72f 100644 --- a/buildSrc/src/main/groovy/fabric-api.root-publishing.gradle +++ b/buildSrc/src/main/groovy/fabric-api.root-publishing.gradle @@ -84,6 +84,8 @@ publishMods { accessToken = providers.environmentVariable("CURSEFORGE_API_KEY") projectId = "306612" project.curseforge_minecraft_versions.split(",").each { minecraftVersions.add(it.trim()) } + client = true + server = true } modrinth { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c16ed156744..12ed3d9ae8b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,7 +4,7 @@ fabric-installer = "1.0.1" fabric-loom = "1.17.0-alpha.19" spotless = "8.6.0" remote-sign = "0.5.0" -mod-publish = "2.0.0-beta.1" +mod-publish = "2.0.0" checkstyle = "13.5.0" mockito = "5.23.0" From 01729eae17b590ea818893486d168374cb3d0e24 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Sat, 6 Jun 2026 10:39:42 +0100 Subject: [PATCH 20/23] Publishing fixes and cleanup --- ...adle => fabric-api.base-publishing.gradle} | 0 .../groovy/fabric-api.deprecated-bom.gradle | 28 +++++++++++-------- .../main/groovy/fabric-api.maven-bom.gradle | 2 +- .../main/groovy/fabric-api.publishing.gradle | 21 +------------- .../groovy/fabric-api.root-publishing.gradle | 13 ++++++++- fabric-api-catalog/build.gradle | 2 +- 6 files changed, 32 insertions(+), 34 deletions(-) rename buildSrc/src/main/groovy/{fabric-api.meta-publishing.gradle => fabric-api.base-publishing.gradle} (100%) diff --git a/buildSrc/src/main/groovy/fabric-api.meta-publishing.gradle b/buildSrc/src/main/groovy/fabric-api.base-publishing.gradle similarity index 100% rename from buildSrc/src/main/groovy/fabric-api.meta-publishing.gradle rename to buildSrc/src/main/groovy/fabric-api.base-publishing.gradle diff --git a/buildSrc/src/main/groovy/fabric-api.deprecated-bom.gradle b/buildSrc/src/main/groovy/fabric-api.deprecated-bom.gradle index d90f7f376de..30776087baa 100644 --- a/buildSrc/src/main/groovy/fabric-api.deprecated-bom.gradle +++ b/buildSrc/src/main/groovy/fabric-api.deprecated-bom.gradle @@ -2,11 +2,22 @@ import net.fabricmc.fabric.impl.build.FabricApiBuildUtils import org.gradle.api.publish.maven.MavenPublication plugins { - id "fabric-api.meta-publishing" + id "fabric-api.base-publishing" } version = rootProject.version +def dependencies = rootProject.allprojects.findAll { + it.name != "deprecated" && it.path.startsWith(":deprecated") +}.collect { + [ + 'groupId': it.group.toString(), + 'artifactId': it.name, + 'version': FabricApiBuildUtils.moduleVersion(it), + 'scope': 'compile' + ] +} + publishing { publications { mavenJava(MavenPublication) { @@ -14,17 +25,12 @@ publishing { pom.withXml { def depsNode = asNode().appendNode("dependencies") - - rootProject.allprojects.each { - if (it.name == "deprecated" || !it.path.startsWith(":deprecated")) { - return - } - + for (dep in dependencies) { def depNode = depsNode.appendNode("dependency") - depNode.appendNode("groupId", it.group) - depNode.appendNode("artifactId", it.name) - depNode.appendNode("version", FabricApiBuildUtils.moduleVersion(it)) - depNode.appendNode("scope", "compile") + depNode.appendNode("groupId", dep['groupId']) + depNode.appendNode("artifactId", dep['artifactId']) + depNode.appendNode("version", dep['version']) + depNode.appendNode("scope", dep['scope']) } } } diff --git a/buildSrc/src/main/groovy/fabric-api.maven-bom.gradle b/buildSrc/src/main/groovy/fabric-api.maven-bom.gradle index 9303cee7b4c..8c980f85339 100644 --- a/buildSrc/src/main/groovy/fabric-api.maven-bom.gradle +++ b/buildSrc/src/main/groovy/fabric-api.maven-bom.gradle @@ -2,7 +2,7 @@ import org.gradle.api.publish.maven.MavenPublication plugins { id "java-platform" - id "fabric-api.meta-publishing" + id "fabric-api.base-publishing" } version = rootProject.version diff --git a/buildSrc/src/main/groovy/fabric-api.publishing.gradle b/buildSrc/src/main/groovy/fabric-api.publishing.gradle index 1599adb9274..10af392625a 100644 --- a/buildSrc/src/main/groovy/fabric-api.publishing.gradle +++ b/buildSrc/src/main/groovy/fabric-api.publishing.gradle @@ -2,33 +2,14 @@ import net.fabricmc.fabric.impl.build.FabricApiBuildUtils import org.gradle.api.publish.maven.MavenPublication plugins { - id "maven-publish" - id "me.modmuss50.remotesign" + id "fabric-api.base-publishing" } -group = "net.fabricmc.fabric-api" base { archivesName = project.name } -tasks.withType(GenerateModuleMetadata).configureEach { - enabled = false -} - -remoteSign { - requestUrl = providers.environmentVariable("SIGNING_SERVER") - pgpAuthKey = providers.environmentVariable("SIGNING_PGP_KEY") - jarAuthKey = providers.environmentVariable("SIGNING_JAR_KEY") - useDummyForTesting = !providers.environmentVariable("SIGNING_SERVER").present - - afterEvaluate { - sign publishing.publications.mavenJava - } -} - publishing { - FabricApiBuildUtils.setupRepositories(project, repositories) - publications { mavenJava(MavenPublication) { pom { diff --git a/buildSrc/src/main/groovy/fabric-api.root-publishing.gradle b/buildSrc/src/main/groovy/fabric-api.root-publishing.gradle index 702c4f0a72f..109d5f7cb64 100644 --- a/buildSrc/src/main/groovy/fabric-api.root-publishing.gradle +++ b/buildSrc/src/main/groovy/fabric-api.root-publishing.gradle @@ -4,7 +4,7 @@ import org.gradle.api.publish.maven.MavenPublication import org.gradle.external.javadoc.JavadocMemberLevel plugins { - id "fabric-api.publishing" + id "fabric-api.base-publishing" id "me.modmuss50.mod-publish-plugin" } @@ -49,6 +49,17 @@ tasks.register('javadocJar', Jar) { build.dependsOn javadocJar +remoteSign { + sign jar +} + +String archivesName = project.base.archivesName.get() +[jar, sourcesJar].each { + it.from(rootProject.file("LICENSE")) { + rename { "${it}-${archivesName}" } + } +} + publishing { publications { mavenJava(MavenPublication) { diff --git a/fabric-api-catalog/build.gradle b/fabric-api-catalog/build.gradle index 6ba82d7bb23..bc77070d771 100644 --- a/fabric-api-catalog/build.gradle +++ b/fabric-api-catalog/build.gradle @@ -2,7 +2,7 @@ import org.gradle.api.publish.maven.MavenPublication plugins { id "version-catalog" - id "fabric-api.meta-publishing" + id "fabric-api.base-publishing" } version = rootProject.version From 2df8fa536fe370a5b3b95956312f757a10a341e0 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Sat, 6 Jun 2026 10:43:30 +0100 Subject: [PATCH 21/23] Fix focus script --- gradle/Focus.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/Focus.java b/gradle/Focus.java index 294ad5b983f..9a178fbc07c 100644 --- a/gradle/Focus.java +++ b/gradle/Focus.java @@ -35,7 +35,7 @@ */ public class Focus { // Matches the content of moduleDependencies and testDependencies - private static final Pattern OUTER_PATTERN = Pattern.compile("(?:moduleDependencies|testDependencies)\\s*\\(.*?\\[\\s*([\\s\\S]*?)\\s*\\]\\s*\\)\n"); + private static final Pattern OUTER_PATTERN = Pattern.compile("(?:moduleDependencies|testDependencies)\\s*\\(\\s*([\\s\\S]*?)\\s*\\)"); // Matches the dependency string private static final Pattern INNER_PATTERN = Pattern.compile("['\\\"]([^'\\\"]+)['\\\"]"); From a4311bb5c38a34af54610404e1bf12303e76507e Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Sat, 6 Jun 2026 10:56:09 +0100 Subject: [PATCH 22/23] Checkstyle fixes --- buildSrc/build.gradle | 5 +++++ .../build/AbstractGenerateClassTweakerTask.java | 14 +++++++++----- .../fabric/impl/build/BumpVersionTask.java | 13 +++++++------ .../fabric/impl/build/FabricApiBuildUtils.java | 16 +++++++++------- .../fabric/impl/build/ValidateModuleTask.java | 3 ++- 5 files changed, 32 insertions(+), 19 deletions(-) diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 572cde3454f..af6d71b26b3 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -26,6 +26,7 @@ spotless { lineEndings = com.diffplug.spotless.LineEnding.UNIX java { + target("src/main/java/**/*.java") licenseHeaderFile(file("../HEADER")) removeUnusedImports() importOrder('java', 'javax', '', 'net.minecraft', 'net.fabricmc') @@ -33,3 +34,7 @@ spotless { trimTrailingWhitespace() } } + +tasks.withType(Checkstyle).configureEach { + source = fileTree("src/main/java") +} diff --git a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/AbstractGenerateClassTweakerTask.java b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/AbstractGenerateClassTweakerTask.java index ac60fda9b76..2bdcec2a1b5 100644 --- a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/AbstractGenerateClassTweakerTask.java +++ b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/AbstractGenerateClassTweakerTask.java @@ -18,11 +18,15 @@ import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.TreeMap; +import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.gradle.api.DefaultTask; @@ -65,7 +69,7 @@ protected void addHeader(List lines, String format, boolean preserveTemp lines.add("# DO NOT EDIT BY HAND! This file is generated automatically."); lines.add("# Edit \"template.classtweaker\" instead then run \"gradlew generateClassTweaker\"."); lines.add(""); - var template = getTemplate().get().getAsFile().toPath(); + Path template = getTemplate().get().getAsFile().toPath(); lines.addAll(Files.readAllLines(template, StandardCharsets.UTF_8)); if (preserveTemplateTrailingNewline && Files.readString(template, StandardCharsets.UTF_8).endsWith("\n")) { @@ -107,8 +111,8 @@ protected List readPackageClasses(String packageName) throws IOExcept private static void readClasses(File input, Map classes) throws IOException { try (ZipFile zip = new ZipFile(input)) { - for (var entries = zip.entries(); entries.hasMoreElements(); ) { - var entry = entries.nextElement(); + for (Enumeration entries = zip.entries(); entries.hasMoreElements(); ) { + ZipEntry entry = entries.nextElement(); if (!entry.getName().endsWith(".class")) { continue; @@ -154,13 +158,13 @@ private static List readPackageClasses(File input, String packageName } private static ClassNode readClass(ZipFile zip, String path, int flags) throws IOException { - var entry = zip.getEntry(path); + ZipEntry entry = zip.getEntry(path); if (entry == null) { throw new IOException("Missing class " + path + " in " + zip.getName()); } - try (var inputStream = zip.getInputStream(entry)) { + try (InputStream inputStream = zip.getInputStream(entry)) { ClassReader reader = new ClassReader(inputStream); ClassNode classNode = new ClassNode(); reader.accept(classNode, flags); diff --git a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/BumpVersionTask.java b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/BumpVersionTask.java index 4fb7b7269f8..6b287b3e267 100644 --- a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/BumpVersionTask.java +++ b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/BumpVersionTask.java @@ -16,10 +16,11 @@ package net.fabricmc.fabric.impl.build; +import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.LinkedHashMap; -import java.util.List; +import java.util.Map; import java.util.Scanner; import org.gradle.api.DefaultTask; @@ -53,11 +54,11 @@ public BumpVersionTask() { @TaskAction public void runTask() throws IOException { - var toUpdate = new LinkedHashMap(); + LinkedHashMap toUpdate = new LinkedHashMap<>(); readInteractiveUpdates(toUpdate); while (true) { - var temp = new LinkedHashMap(); + LinkedHashMap temp = new LinkedHashMap<>(); for (String projectName : toUpdate.keySet()) { getApiDependencies().get().forEach((childProjectName, dependencies) -> { @@ -75,10 +76,10 @@ public void runTask() throws IOException { toUpdate.putAll(temp); } - var gradlePropertiesFile = getGradlePropertiesFile().get().getAsFile(); + File gradlePropertiesFile = getGradlePropertiesFile().get().getAsFile(); String text = java.nio.file.Files.readString(gradlePropertiesFile.toPath(), StandardCharsets.UTF_8); - for (var entry : toUpdate.entrySet()) { + for (Map.Entry entry : toUpdate.entrySet()) { String projectName = entry.getKey(); int index = entry.getValue(); String version = getModuleVersions().get().get(projectName); @@ -103,7 +104,7 @@ public void runTask() throws IOException { } private void readInteractiveUpdates(LinkedHashMap toUpdate) { - var scanner = new Scanner(System.in); + Scanner scanner = new Scanner(System.in); while (true) { System.out.println("Enter module name to update, or done to continue"); diff --git a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiBuildUtils.java b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiBuildUtils.java index ecbfbb13db9..0e53c10c63a 100644 --- a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiBuildUtils.java +++ b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/FabricApiBuildUtils.java @@ -16,6 +16,7 @@ package net.fabricmc.fabric.impl.build; +import java.io.File; import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; @@ -26,6 +27,7 @@ import java.security.NoSuchAlgorithmException; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import groovy.json.JsonSlurper; @@ -70,7 +72,7 @@ public static String projectPath(String notation) { } public static String rootVersion(Project project) { - var branchProvider = project.getProviders().of(GitBranchValueSource.class, spec -> { }); + Provider branchProvider = project.getProviders().of(GitBranchValueSource.class, spec -> { }); String suffix = project.getProviders().environmentVariable("CI").isPresent() ? branchProvider.get().replace("/", "_") : "local"; @@ -88,7 +90,7 @@ public static String moduleVersion(Project project) { return version + "+local"; } - var hashProvider = project.getProviders().of(CommitHashValueSource.class, spec -> { + Provider hashProvider = project.getProviders().of(CommitHashValueSource.class, spec -> { spec.getParameters().getDirectory().set(project.getName()); }); @@ -128,19 +130,19 @@ public static boolean publishedArtifactExists(Project project, String projectNam } String artifactPath = "https://maven.fabricmc.net/net/fabricmc/fabric-api/%s/%s/%s-%s.pom".formatted(projectName, projectVersion, projectName, projectVersion); - var request = HttpRequest.newBuilder() + HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(artifactPath)) .method("HEAD", HttpRequest.BodyPublishers.noBody()) .build(); - try (var client = HttpClient.newHttpClient()) { + try (HttpClient client = HttpClient.newHttpClient()) { HttpResponse response = client.send(request, HttpResponse.BodyHandlers.discarding()); return response.statusCode() == 200; } } public static void addPomMetadataInformation(Project project, MavenPom pom) { - var modJsonFile = project.file("src/main/resources/fabric.mod.json"); + File modJsonFile = project.file("src/main/resources/fabric.mod.json"); if (!modJsonFile.exists()) { modJsonFile = project.file("src/client/resources/fabric.mod.json"); @@ -176,7 +178,7 @@ public static void appendPomDependencies(Node pomNode, List> for (Map dependency : dependencies) { Node depNode = depsNode.appendNode("dependency"); - for (var entry : dependency.entrySet()) { + for (Entry entry : dependency.entrySet()) { depNode.appendNode(entry.getKey(), entry.getValue()); } } @@ -185,7 +187,7 @@ public static void appendPomDependencies(Node pomNode, List> private static String sha256Hex(String input) { try { byte[] digest = MessageDigest.getInstance("SHA-256").digest(input.getBytes(StandardCharsets.UTF_8)); - var builder = new StringBuilder(digest.length * 2); + StringBuilder builder = new StringBuilder(digest.length * 2); for (byte value : digest) { builder.append(String.format("%02x", value)); diff --git a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/ValidateModuleTask.java b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/ValidateModuleTask.java index bfdcd63df86..27f6de4071d 100644 --- a/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/ValidateModuleTask.java +++ b/buildSrc/src/main/java/net/fabricmc/fabric/impl/build/ValidateModuleTask.java @@ -16,6 +16,7 @@ package net.fabricmc.fabric.impl.build; +import java.io.File; import java.util.Map; import groovy.json.JsonSlurper; @@ -44,7 +45,7 @@ public ValidateModuleTask() { setGroup("verification"); getOutputs().upToDateWhen(task -> true); - var file = getProject().file("src/main/resources/fabric.mod.json"); + File file = getProject().file("src/main/resources/fabric.mod.json"); if (!file.exists()) { file = getProject().file("src/client/resources/fabric.mod.json"); From 5b43a640b221981be5168b4f3bdcd2195a672768 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Sat, 6 Jun 2026 11:01:07 +0100 Subject: [PATCH 23/23] Deprecation fix --- buildSrc/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index af6d71b26b3..8b36645ebc4 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -30,7 +30,7 @@ spotless { licenseHeaderFile(file("../HEADER")) removeUnusedImports() importOrder('java', 'javax', '', 'net.minecraft', 'net.fabricmc') - indentWithTabs() + leadingSpacesToTabs() trimTrailingWhitespace() } }