diff --git a/build.gradle b/build.gradle index d63f04364..db58217e4 100644 --- a/build.gradle +++ b/build.gradle @@ -270,6 +270,11 @@ test { maxRetries = 3 } } + + testLogging { + // Log everything to the console + setEvents(TestLogEvent.values().toList()) + } } // Workaround https://github.com/gradle/gradle/issues/25898 @@ -283,7 +288,7 @@ tasks.withType(Test).configureEach { } -import org.gradle.api.internal.artifacts.configurations.ConfigurationRoles +import org.gradle.api.tasks.testing.logging.TestLogEvent import org.gradle.util.GradleVersion import org.w3c.dom.Document import org.w3c.dom.Element diff --git a/src/main/java/net/fabricmc/loom/task/prod/ClientProductionRunTask.java b/src/main/java/net/fabricmc/loom/task/prod/ClientProductionRunTask.java index f608fea0c..01779a857 100644 --- a/src/main/java/net/fabricmc/loom/task/prod/ClientProductionRunTask.java +++ b/src/main/java/net/fabricmc/loom/task/prod/ClientProductionRunTask.java @@ -43,6 +43,16 @@ */ @ApiStatus.Experimental public abstract non-sealed class ClientProductionRunTask extends AbstractProductionRunTask { + /** + * Whether to use XVFB to run the game, using a virtual framebuffer. This is useful for CI environments that don't have a display server. + * + *

Defaults to true only on Linux and when the "CI" environment variable is set. + * + *

XVFB must be installed, on Debian-based systems you can install it with: apt install -y xvfb + */ + @Input + public abstract Property getUseXVFB(); + // Internal options @Input protected abstract Property getAssetsIndex(); @@ -52,6 +62,11 @@ public abstract non-sealed class ClientProductionRunTask extends AbstractProduct @Inject public ClientProductionRunTask() { + getUseXVFB().convention(getProject().getProviders().environmentVariable("CI") + .map(value -> Platform.CURRENT.getOperatingSystem().isLinux()) + .orElse(false) + ); + getAssetsIndex().set(getExtension().getMinecraftVersion() .map(minecraftVersion -> getExtension() .getMinecraftProvider() @@ -71,6 +86,22 @@ public ClientProductionRunTask() { dependsOn("downloadAssets"); } + @Override + protected void configureCommand(ExecSpec exec) { + if (getUseXVFB().get()) { + if (!Platform.CURRENT.getOperatingSystem().isLinux()) { + throw new UnsupportedOperationException("XVFB is only supported on Linux"); + } + + exec.commandLine("/usr/bin/xvfb-run"); + exec.args("-a", getJavaLauncher().get().getExecutablePath()); + + return; + } + + super.configureCommand(exec); + } + @Override protected void configureJvmArgs(ExecSpec exec) { super.configureJvmArgs(exec); diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/RunConfigTest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/RunConfigTest.groovy index 77ee9e503..95b8f0118 100644 --- a/src/test/groovy/net/fabricmc/loom/test/integration/RunConfigTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/integration/RunConfigTest.groovy @@ -24,8 +24,11 @@ package net.fabricmc.loom.test.integration +import java.util.concurrent.TimeUnit + import spock.lang.IgnoreIf import spock.lang.Specification +import spock.lang.Timeout import spock.lang.Unroll import spock.util.environment.RestoreSystemProperties @@ -157,19 +160,30 @@ class RunConfigTest extends Specification implements GradleProjectTestTrait { version << STANDARD_TEST_VERSIONS } + @Timeout(value = 10, unit = TimeUnit.MINUTES) @Unroll - @IgnoreIf({ System.getenv("CI") != null }) // This test is disabled on CI because it launches a real client and cannot run headless. + @IgnoreIf({ !os.linux }) // XVFB is installed on the CI for this test def "prod client (gradle #version)"() { setup: def gradle = gradleProject(project: "minimalBase", version: version) gradle.buildGradle << ''' + configurations { + productionMods + } + dependencies { minecraft "com.mojang:minecraft:1.21.4" mappings "net.fabricmc:yarn:1.21.4+build.4:v2" modImplementation "net.fabricmc:fabric-loader:0.16.9" + modImplementation "net.fabricmc.fabric-api:fabric-api:0.114.0+1.21.4" + + productionMods "net.fabricmc.fabric-api:fabric-api:0.114.0+1.21.4" } - tasks.register("prodClient", net.fabricmc.loom.task.prod.ClientProductionRunTask) + tasks.register("prodClient", net.fabricmc.loom.task.prod.ClientProductionRunTask) { + mods.from(configurations.productionMods) + jvmArgs.add("-Dfabric.client.gametest") + } ''' when: def result = gradle.run(task: "prodClient")