Loom 1.10, remove grgit, work towards config caching. ()

* Update to Loom 1.10 and use new prod run tasks

* Fixes

* Remove grgit

* Fix build?

* Fix build?

* Loom 1.10, Remove grgit, work towards config caching.

* Try without tracy?

* Fix version catalog

* Fix local version
This commit is contained in:
modmuss 2025-02-15 14:46:29 +00:00 committed by GitHub
parent 504c6f623c
commit d1118d9789
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 279 additions and 228 deletions

View file

@ -5,17 +5,17 @@ jobs:
strategy:
matrix:
java: [21-ubuntu]
runs-on: ubuntu-22.04
container:
image: mcr.microsoft.com/openjdk/jdk:${{ matrix.java }}
options: --user root
runs-on: ubuntu-24.04
steps:
- run: apt update && apt install git -y && git --version
- uses: actions/setup-java@v4
with:
distribution: 'microsoft'
java-version: '21'
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: gradle/wrapper-validation-action@v2
- run: ./gradlew check build publishToMavenLocal --stacktrace
- run: ./gradlew check build :buildSrc:check publishToMavenLocal --stacktrace --configuration-cache
- uses: Juuxel/publish-checkstyle-report@v1
if: ${{ failure() }}
with:
@ -31,10 +31,10 @@ jobs:
- uses: actions/upload-artifact@v4
with:
name: Maven Local ${{ matrix.java }}
path: /root/.m2/repository/net/fabricmc/
path: ~/.m2/repository/net/fabricmc/
client_test:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
with:
@ -43,19 +43,26 @@ jobs:
with:
distribution: 'microsoft'
java-version: '21'
- run: mkdir run && echo "eula=true" >> run/eula.txt
- name: Run Client Gametests
uses: modmuss50/xvfb-action@v1
with:
run: ./gradlew runProductionClientGametest --stacktrace --warning-mode=fail
- run: |
curl -L -o tracy-capture https://github.com/modmuss50/tracy-utils/releases/download/0.0.2/linux-x86_64-tracy-capture
chmod +x tracy-capture
mkdir run && echo "eula=true" >> run/eula.txt
- run: ./gradlew runProductionClientGametest --stacktrace --warning-mode=fail
env:
ENABLE_TRACY_NO: true
- uses: actions/upload-artifact@v4
if: always()
with:
name: Test Screenshots
path: run/screenshots
- uses: actions/upload-artifact@v4
if: always()
with:
name: Tracy Profile
path: profile.tracy
server_test:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
with:
@ -68,7 +75,7 @@ jobs:
- run: ./gradlew runProductionAutoTestServer --stacktrace --warning-mode=fail
check_resources:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
with:

View file

@ -6,7 +6,7 @@ on:
jobs:
labels:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: FabricMC/fabric-action-scripts@v2
with:

View file

@ -6,13 +6,12 @@ permissions:
jobs:
build:
runs-on: ubuntu-22.04
container:
image: mcr.microsoft.com/openjdk/jdk:21-ubuntu
options: --user root
runs-on: ubuntu-24.04
steps:
- run: apt update && apt install git -y && git --version
- run: git config --global --add safe.directory /__w/fabric/fabric
- uses: actions/setup-java@v4
with:
distribution: 'microsoft'
java-version: '21'
- uses: actions/checkout@v4
with:
fetch-depth: 0
@ -22,7 +21,7 @@ jobs:
context: changelog
workflow_id: release.yml
- uses: gradle/wrapper-validation-action@v2
- run: ./gradlew checkVersion build publish publishMods --stacktrace
- run: ./gradlew checkVersion build publish publishMods --stacktrace --no-configuration-cache
env:
MAVEN_URL: ${{ secrets.MAVEN_URL }}
MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}

2
.gitignore vendored
View file

@ -43,3 +43,5 @@ $RECYCLE.BIN/
# Mac
.DS_Store
!/buildSrc/src/**

View file

@ -1,19 +1,15 @@
plugins {
id "java-library"
id "eclipse"
id "idea"
id "maven-publish"
id 'jacoco'
id "fabric-loom" version "1.9.2" apply false
id "com.diffplug.spotless" version "6.20.0"
id "org.ajoberstar.grgit" version "5.2.2"
id "fabric-loom" version "1.10.1" apply false
id "com.diffplug.spotless" version "7.0.2"
id "me.modmuss50.remotesign" version "0.5.0" apply false
id "me.modmuss50.mod-publish-plugin" version "0.4.5"
}
def ENV = System.getenv()
version = project.version + "+" + (ENV.GITHUB_RUN_NUMBER ? "" : "local-") + getBranch()
def branchProvider = providers.of(GitBranchValueSource.class) {}
version = project.version + "+" + (providers.environmentVariable("CI").present ? branchProvider.get() : "local")
logger.lifecycle("Building Fabric: " + version)
def metaProjects = [
@ -29,11 +25,12 @@ def debugArgs = [
"-Dmixin.debug.countInjections=true",
]
import net.fabricmc.loom.util.gradle.SourceSetHelper
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
def getSubprojectVersion(project) {
def getSubprojectVersion(Project project) {
// Get the version from the gradle.properties file
def version = project.properties["${project.name}-version"]
@ -41,32 +38,14 @@ def getSubprojectVersion(project) {
throw new NullPointerException("Could not find version for " + project.name)
}
if (grgit == null) {
return version + "+nogit"
if (!project.providers.environmentVariable("CI").present) {
return version + "+local"
}
def latestCommits = grgit.log(paths: [project.name], maxCommits: 1)
if (latestCommits.isEmpty()) {
return version + "+uncommited"
def hashProvider = project.providers.of(CommitHashValueSource.class) {
parameters.directory = project.name
}
return version + "+" + latestCommits.get(0).id.substring(0, 8) + DigestUtils.sha256Hex(project.rootProject.minecraft_version).substring(0, 2)
}
def getBranch() {
def ENV = System.getenv()
if (ENV.GITHUB_REF) {
def branch = ENV.GITHUB_REF
return branch.substring(branch.lastIndexOf("/") + 1)
}
if (grgit == null) {
return "unknown"
}
def branch = grgit.branch.current().name
return branch.substring(branch.lastIndexOf("/") + 1)
return version + "+" + hashProvider.get().substring(0, 8) + DigestUtils.sha256Hex(project.rootProject.minecraft_version).substring(0, 2)
}
def moduleDependencies(project, List<String> depNames) {
@ -83,18 +62,28 @@ def moduleDependencies(project, List<String> depNames) {
}
}
def depNodes = deps.collect {
[
groupId: it.group,
artifactId: it.name,
version: it.version,
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")
deps.each {
def depNode = depsNode.appendNode("dependency")
depNode.appendNode("groupId", it.group)
depNode.appendNode("artifactId", it.name)
depNode.appendNode("version", it.version)
depNode.appendNode("scope", "compile")
for (def depNode in depNodes) {
def node = depsNode.appendNode("dependency")
for (def entry in depNode) {
node.appendNode(entry.key, entry.value)
}
}
}
}
@ -128,11 +117,11 @@ allprojects {
}
remoteSign {
requestUrl = ENV.SIGNING_SERVER
pgpAuthKey = ENV.SIGNING_PGP_KEY
jarAuthKey = ENV.SIGNING_JAR_KEY
requestUrl = providers.environmentVariable("SIGNING_SERVER")
pgpAuthKey = providers.environmentVariable("SIGNING_PGP_KEY")
jarAuthKey = providers.environmentVariable("SIGNING_JAR_KEY")
useDummyForTesting = ENV.SIGNING_SERVER == null
useDummyForTesting = !providers.environmentVariable("SIGNING_SERVER").present
afterEvaluate {
// PGP sign all maven publications.
@ -249,11 +238,12 @@ allprojects {
useJUnitPlatform()
}
def resourceVersion = project.version
tasks.withType(ProcessResources).configureEach {
inputs.property "version", project.version
inputs.property "version", resourceVersion
filesMatching("fabric.mod.json") {
expand "version": project.version
expand "version": resourceVersion
}
}
@ -264,7 +254,7 @@ allprojects {
licenseHeaderFile(rootProject.file("HEADER"))
removeUnusedImports()
importOrder('java', 'javax', '', 'net.minecraft', 'net.fabricmc')
indentWithTabs()
leadingSpacesToTabs()
trimTrailingWhitespace()
}
@ -303,19 +293,20 @@ allprojects {
archiveClassifier = "testmod"
}
String archivesName = project.base.archivesName.get()
[jar, sourcesJar].each {
it.from(rootProject.file("LICENSE")) {
rename { "${it}-${project.base.archivesName.get()}"}
rename { "${it}-${archivesName}"}
}
}
if (file("src/client").exists() && !file("src/main").exists()) {
remapJar {
additionalClientOnlyEntries.add("LICENSE-${project.base.archivesName.get()}")
tasks.named("remapJar", net.fabricmc.loom.task.AbstractRemapJarTask) {
additionalClientOnlyEntries.add("LICENSE-${archivesName}".toString())
}
remapSourcesJar {
additionalClientOnlyEntries.add("LICENSE-${project.base.archivesName.get()}")
additionalClientOnlyEntries.add("LICENSE-${archivesName}".toString())
}
}
@ -432,19 +423,6 @@ loom {
vmArg "-Dfabric-tag-conventions-v2.missingTagTranslationWarning=fail"
vmArg "-Dfabric-tag-conventions-v1.legacyTagWarning=fail"
}
// Create duplicate tasks for this, as jacoco slows things down a bit
gametestCoverage {
inherit gametest
name "Game Test Coverage"
ideConfigGenerated = false
}
clientGametestCoverage {
inherit clientGametest
name "Client Game Test Coverage"
ideConfigGenerated = false
}
}
}
@ -454,126 +432,40 @@ runGametest {
test.dependsOn runGametest
def coverageTasks = [
runGametestCoverage,
runClientGametestCoverage
]
jacoco {
coverageTasks.forEach {
applyTo it
}
}
tasks.register('coverage', JacocoReport) {
dependsOn coverageTasks
coverageTasks.forEach {
executionData it
}
// Add all source as input
allprojects { p ->
if (p.path.startsWith(":deprecated") || metaProjects.contains(p.name)) {
return
}
sourceSets p.sourceSets.main, p.sourceSets.client, p.sourceSets.testmod, p.sourceSets.testmodClient
}
// Exclude mixins
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it, exclude: '**/mixin/**')
}))
}
configurations {
productionRuntime {
extendsFrom configurations.minecraftLibraries
extendsFrom configurations.loaderLibraries
extendsFrom configurations.minecraftRuntimeLibraries
}
productionRuntimeServer
productionMods {
transitive = false
}
}
dependencies {
productionRuntime "net.fabricmc:fabric-loader:${project.loader_version}"
productionRuntime "net.fabricmc:intermediary:${project.minecraft_version}"
productionRuntimeServer "net.fabricmc:fabric-installer:${project.installer_version}:server"
productionMods project(':fabric-client-gametest-api-v1')
}
import net.fabricmc.loom.util.Platform
def productionMods = project.files(configurations.productionMods, remapJar.archiveFile, remapTestmodJar.archiveFile)
// This is very far beyond loom's API if you copy this, you're on your own.
tasks.register('runProductionClientGametest', JavaExec) {
dependsOn productionMods, downloadAssets
classpath.from configurations.productionRuntime
mainClass = "net.fabricmc.loader.impl.launch.knot.KnotClient"
workingDir = file("run")
tasks.register('runProductionClientGametest', net.fabricmc.loom.task.prod.ClientProductionRunTask) {
mods.setFrom productionMods
jvmArgs.addAll([
"-Dfabric.client.gametest",
"-Dfabric-tag-conventions-v2.missingTagTranslationWarning=fail",
"-Dfabric-tag-conventions-v1.legacyTagWarning=fail"
])
jvmArgs.addAll(debugArgs)
doFirst {
classpath.from loom.minecraftProvider.minecraftClientJar
workingDir.mkdirs()
args(
"--assetIndex", loom.minecraftProvider.versionInfo.assetIndex().fabricId(loom.minecraftProvider.minecraftVersion()),
"--assetsDir", new File(loom.files.userCache, "assets").absolutePath,
"--gameDir", workingDir.absolutePath
)
if (Platform.CURRENT.operatingSystem.isMacOS()) {
jvmArgs(
"-XstartOnFirstThread"
)
if (providers.environmentVariable("ENABLE_TRACY").present) {
tracy {
tracyCapture = file("tracy-capture")
output = file("profile.tracy")
}
jvmArgs(
"-Dfabric.addMods=${productionMods.collect { it.absolutePath }.join(File.pathSeparator)}",
"-Dfabric.client.gametest",
"-Dfabric-tag-conventions-v2.missingTagTranslationWarning=fail",
"-Dfabric-tag-conventions-v1.legacyTagWarning=fail"
)
jvmArgs(debugArgs)
}
}
tasks.register('serverPropertiesJar', Jar) {
def propsFile = file("build/tmp/install.properties")
doFirst {
propsFile.text = """\
fabric-loader-version=${project.loader_version}
game-version=${project.minecraft_version}
""".stripMargin().stripIndent()
}
archiveFileName = "test-server-properties.jar"
destinationDirectory = file("build/tmp")
from(propsFile)
}
tasks.register('runProductionAutoTestServer', JavaExec) {
dependsOn productionMods, serverPropertiesJar
classpath.from configurations.productionRuntimeServer, serverPropertiesJar
mainClass = "net.fabricmc.installer.ServerLauncher"
workingDir = file("run")
doFirst {
workingDir.mkdirs()
jvmArgs(
"-Dfabric.addMods=${productionMods.collect { it.absolutePath }.join(File.pathSeparator)}",
"-Dfabric.autoTest",
)
jvmArgs(debugArgs)
args("nogui")
}
tasks.register('runProductionAutoTestServer', net.fabricmc.loom.task.prod.ServerProductionRunTask) {
mods.setFrom productionMods
jvmArgs.add("-Dfabric.autoTest")
jvmArgs.addAll(debugArgs)
programArgs.add("nogui")
}
// Format all the gradle files
@ -686,26 +578,40 @@ publishing {
addPomMetadataInformation(rootProject, pom)
}
List<Map<String, String>> 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': it.version,
'scope': 'compile'
])
}
def thisGroup = group
def thisVersion = version
pom.withXml {
def depsNode = asNode().appendNode("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
}
for (dep in dependencies) {
def depNode = depsNode.appendNode("dependency")
depNode.appendNode("groupId", it.group)
depNode.appendNode("artifactId", it.name)
depNode.appendNode("version", it.version)
depNode.appendNode("scope", "compile")
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", group)
depNode.appendNode("groupId", thisGroup)
depNode.appendNode("artifactId", "fabric-api-deprecated")
depNode.appendNode("version", version)
depNode.appendNode("version", thisVersion)
depNode.appendNode("scope", "compile")
}
}
@ -717,15 +623,12 @@ loom.disableDeprecatedPomGeneration(publishing.publications.mavenJava)
void setupRepositories(RepositoryHandler repositories) {
//repositories.mavenLocal() // uncomment for testing
def ENV = System.getenv()
if (ENV.MAVEN_URL) {
if (providers.environmentVariable("MAVEN_URL").present) {
repositories.maven {
url ENV.MAVEN_URL
if (ENV.MAVEN_USERNAME) {
credentials {
username ENV.MAVEN_USERNAME
password ENV.MAVEN_PASSWORD
}
url = providers.environmentVariable("MAVEN_URL")
credentials {
username = providers.environmentVariable("MAVEN_USERNAME")
password = providers.environmentVariable("MAVEN_PASSWORD")
}
}
}

25
buildSrc/build.gradle Normal file
View file

@ -0,0 +1,25 @@
plugins {
id 'checkstyle'
id "com.diffplug.spotless" version "6.20.0"
}
repositories {
mavenCentral()
}
checkstyle {
configFile = file("../checkstyle.xml")
toolVersion = "10.20.2"
}
spotless {
lineEndings = com.diffplug.spotless.LineEnding.UNIX
java {
licenseHeaderFile(file("../HEADER"))
removeUnusedImports()
importOrder('java', 'javax', '', 'net.minecraft', 'net.fabricmc')
indentWithTabs()
trimTrailingWhitespace()
}
}

View file

@ -0,0 +1,42 @@
/*
* 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.ByteArrayOutputStream;
import javax.inject.Inject;
import org.gradle.api.provider.ValueSource;
import org.gradle.api.provider.ValueSourceParameters;
import org.gradle.process.ExecOperations;
import org.gradle.process.ExecResult;
public abstract class AbstractGitValueSource<T, P extends ValueSourceParameters> implements ValueSource<T, P> {
@Inject
protected abstract ExecOperations getExecOperations();
protected String git(String... args) {
var outputStream = new ByteArrayOutputStream();
ExecResult result = getExecOperations().exec(spec -> {
spec.commandLine("git");
spec.args((Object[]) args);
spec.setStandardOutput(outputStream);
});
result.assertNormalExitValue();
return outputStream.toString().trim();
}
}

View file

@ -0,0 +1,31 @@
/*
* 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 org.gradle.api.provider.Property;
import org.gradle.api.provider.ValueSourceParameters;
public abstract class CommitHashValueSource extends AbstractGitValueSource<String, CommitHashValueSource.Parameters> {
public interface Parameters extends ValueSourceParameters {
Property<String> getDirectory();
}
@Override
public String obtain() {
return git("log", "-1", "--format=%H", "--", getParameters().getDirectory().get());
}
}

View file

@ -0,0 +1,26 @@
/*
* 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 org.gradle.api.provider.ValueSourceParameters;
public abstract class GitBranchValueSource extends AbstractGitValueSource<String, ValueSourceParameters.None> {
@Override
public String obtain() {
return git("rev-parse", "--abbrev-ref", "HEAD");
}
}

View file

@ -8,26 +8,44 @@ publishing {
mavenJava(MavenPublication) {
artifactId = 'fabric-api-deprecated'
List<Map<String, String>> 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': it.version,
'scope': 'compile'
])
}
def thisGroup = group
def thisVersion = version
pom.withXml {
def depsNode = asNode().appendNode("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
def depNode = depsNode.appendNode("dependency")
depNode.appendNode("groupId", it.group)
depNode.appendNode("artifactId", it.name)
depNode.appendNode("version", it.version)
depNode.appendNode("scope", "compile")
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 main project.
def depNode = depsNode.appendNode("dependency")
depNode.appendNode("groupId", group)
depNode.appendNode("groupId", thisGroup)
depNode.appendNode("artifactId", "fabric-api")
depNode.appendNode("version", version)
depNode.appendNode("version", thisVersion)
depNode.appendNode("scope", "compile")
}
}

View file

@ -17,10 +17,9 @@ tasks.withType(GenerateModuleMetadata) {
// Avoid configuration ordering issues by creating the catalog entries during task execution time
tasks.register('configureCatalog') {
doFirst {
doConfigureCatalog()
}
doConfigureCatalog()
}
tasks.named('generateCatalogAsToml') {
dependsOn('configureCatalog')
}

View file

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

3
gradlew vendored
View file

@ -86,8 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum