mirror of
https://github.com/architectury/architectury-loom.git
synced 2026-04-02 05:27:43 -05:00
Add versions used to compile/build against to jar manifest (#428)
* Add versions used to compile/build against to jar manifest
* checkstyle
* Move to post remap
* Fix build
* Add mc version and mixin group
* Typo
* Make test run across versions better.
(cherry picked from commit 2259a4efc8)
Signed-off-by: shedaniel <daniel@shedaniel.me>
This commit is contained in:
@@ -2,3 +2,4 @@
|
||||
indent_style = tab
|
||||
ij_continuation_indent_size = 8
|
||||
ij_java_imports_layout = $*,|,java.**,|,javax.**,|,*,|,net.fabricmc.**
|
||||
ij_java_class_count_to_use_import_on_demand = 999
|
||||
|
||||
@@ -39,7 +39,6 @@ import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.cadixdev.lorenz.MappingSet;
|
||||
import org.cadixdev.mercury.Mercury;
|
||||
import org.gradle.api.Action;
|
||||
@@ -53,6 +52,7 @@ import org.gradle.api.tasks.SourceSet;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import net.fabricmc.loom.api.decompilers.LoomDecompiler;
|
||||
import net.fabricmc.loom.configuration.InstallerData;
|
||||
import net.fabricmc.loom.configuration.LoomDependencyManager;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfig;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
|
||||
@@ -106,7 +106,7 @@ public class LoomGradleExtension {
|
||||
private List<String> dataGenMods = new ArrayList<>();
|
||||
private LoomDependencyManager dependencyManager;
|
||||
private JarProcessorManager jarProcessorManager;
|
||||
private JsonObject installerJson;
|
||||
private InstallerData installerData;
|
||||
private MappingSet[] srcMappingCache = new MappingSet[2];
|
||||
private Mercury[] srcMercuryCache = new Mercury[2];
|
||||
private ModPlatform platform;
|
||||
@@ -268,12 +268,12 @@ public class LoomGradleExtension {
|
||||
return unmappedMods;
|
||||
}
|
||||
|
||||
public void setInstallerJson(JsonObject object) {
|
||||
this.installerJson = object;
|
||||
public void setInstallerData(InstallerData data) {
|
||||
this.installerData = data;
|
||||
}
|
||||
|
||||
public JsonObject getInstallerJson() {
|
||||
return installerJson;
|
||||
public InstallerData getInstallerData() {
|
||||
return installerData;
|
||||
}
|
||||
|
||||
public void accessWidener(Object file) {
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
@@ -45,16 +46,16 @@ import net.fabricmc.loom.task.LoomTasks;
|
||||
public class LoomGradlePlugin implements Plugin<Project> {
|
||||
public static boolean refreshDeps;
|
||||
public static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
||||
public static final String LOOM_VERSION = MoreObjects.firstNonNull(LoomGradlePlugin.class.getPackage().getImplementationVersion(), "0.0.0+unknown");
|
||||
|
||||
@Override
|
||||
public void apply(Project project) {
|
||||
String loomVersion = LoomGradlePlugin.class.getPackage().getImplementationVersion();
|
||||
Set<String> loggedVersions = new HashSet<>(Arrays.asList(System.getProperty("loom.printed.logged", "").split(",")));
|
||||
|
||||
if (!loggedVersions.contains(loomVersion)) {
|
||||
loggedVersions.add(loomVersion);
|
||||
if (!loggedVersions.contains(LOOM_VERSION)) {
|
||||
loggedVersions.add(LOOM_VERSION);
|
||||
System.setProperty("loom.printed.logged", String.join(",", loggedVersions));
|
||||
project.getLogger().lifecycle("Architectury Loom: " + loomVersion);
|
||||
project.getLogger().lifecycle("Architectury Loom: " + LOOM_VERSION);
|
||||
project.getLogger().lifecycle("You are using an unstable version of Architectury Loom! Please report any issues found!");
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.plugins.JavaPlugin;
|
||||
import org.gradle.api.plugins.JavaPluginConvention;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.api.tasks.bundling.AbstractArchiveTask;
|
||||
import org.gradle.api.tasks.bundling.Jar;
|
||||
import org.gradle.api.tasks.compile.JavaCompile;
|
||||
import org.gradle.api.tasks.javadoc.Javadoc;
|
||||
@@ -203,7 +202,7 @@ public final class CompileConfiguration {
|
||||
if (extension.remapMod) {
|
||||
RemapConfiguration.setupDefaultRemap(project);
|
||||
} else {
|
||||
AbstractArchiveTask jarTask = (AbstractArchiveTask) project.getTasks().getByName("jar");
|
||||
Jar jarTask = (Jar) project.getTasks().getByName("jar");
|
||||
extension.getUnmappedModCollection().from(jarTask);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2021 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.configuration;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
public final class InstallerData {
|
||||
private final String version;
|
||||
private final JsonObject installerJson;
|
||||
|
||||
InstallerData(String version, JsonObject installerJson) {
|
||||
this.version = version;
|
||||
this.installerJson = installerJson;
|
||||
}
|
||||
|
||||
public String version() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public JsonObject installerJson() {
|
||||
return installerJson;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (obj == null || obj.getClass() != this.getClass()) return false;
|
||||
InstallerData that = (InstallerData) obj;
|
||||
return Objects.equals(this.version, that.version) && Objects.equals(this.installerJson, that.installerJson);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(version, installerJson);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "InstallerData[" + "version=" + version + ", " + "installerJson=" + installerJson + ']';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2021 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.configuration;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import dev.architectury.tinyremapper.TinyRemapper;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Dependency;
|
||||
import org.gradle.util.GradleVersion;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
|
||||
public final class JarManifestConfiguration {
|
||||
private final Project project;
|
||||
|
||||
public JarManifestConfiguration(Project project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
public void configure(Manifest manifest) {
|
||||
// Dont set when running the reproducible build tests as it will break them when anything updates
|
||||
if (Boolean.getBoolean("loom.test.reproducible")) {
|
||||
return;
|
||||
}
|
||||
|
||||
LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class);
|
||||
|
||||
Attributes attributes = manifest.getMainAttributes();
|
||||
Optional<String> tinyRemapperVersion = Optional.ofNullable(TinyRemapper.class.getPackage().getImplementationVersion());
|
||||
|
||||
attributes.putValue("Fabric-Gradle-Version", GradleVersion.current().getVersion());
|
||||
attributes.putValue("Fabric-Loom-Version", LoomGradlePlugin.LOOM_VERSION);
|
||||
attributes.putValue("Fabric-Mixin-Compile-Extensions-Version", Constants.Dependencies.Versions.MIXIN_COMPILE_EXTENSIONS);
|
||||
attributes.putValue("Fabric-Minecraft-Version", extension.getMinecraftProvider().getMinecraftVersion());
|
||||
tinyRemapperVersion.ifPresent(s -> attributes.putValue("Fabric-Tiny-Remapper-Version", s));
|
||||
getLoaderVersion().ifPresent(s -> attributes.putValue("Fabric-Loader-Version", s));
|
||||
|
||||
// This can be overridden by mods if required
|
||||
if (!attributes.containsKey("Fabric-Mixin-Version")) {
|
||||
addMixinVersion(attributes);
|
||||
}
|
||||
}
|
||||
|
||||
private void addMixinVersion(Attributes attributes) {
|
||||
// Not super ideal that this uses the mod compile classpath, should prob look into making this not a thing at somepoint
|
||||
Optional<Dependency> dependency = project.getConfigurations().getByName(Constants.Configurations.LOADER_DEPENDENCIES)
|
||||
.getDependencies()
|
||||
.stream()
|
||||
.filter(dep -> "sponge-mixin".equals(dep.getName()))
|
||||
.findFirst();
|
||||
|
||||
if (!dependency.isPresent()) {
|
||||
project.getLogger().warn("Could not determine Mixin version for jar manifest");
|
||||
return;
|
||||
}
|
||||
|
||||
attributes.putValue("Fabric-Mixin-Version", dependency.get().getVersion());
|
||||
attributes.putValue("Fabric-Mixin-Group", dependency.get().getGroup());
|
||||
}
|
||||
|
||||
private Optional<String> getLoaderVersion() {
|
||||
LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class);
|
||||
|
||||
if (extension.getInstallerData() == null) {
|
||||
project.getLogger().warn("Could not determine fabric loader version for jar manifest");
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(extension.getInstallerData().version());
|
||||
}
|
||||
}
|
||||
@@ -140,27 +140,29 @@ public class LoomDependencyManager {
|
||||
String platformSuffix = extension.isForge() ? "_forge" : "";
|
||||
String mappingsKey = mappingsProvider.getMappingsKey() + platformSuffix;
|
||||
|
||||
if (extension.getInstallerJson() == null && !extension.isForge()) {
|
||||
if (extension.getInstallerData() == null && !extension.isForge()) {
|
||||
//If we've not found the installer JSON we've probably skipped remapping Fabric loader, let's go looking
|
||||
project.getLogger().info("Searching through modCompileClasspath for installer JSON");
|
||||
final Configuration configuration = project.getConfigurations().getByName(Constants.Configurations.MOD_COMPILE_CLASSPATH);
|
||||
|
||||
for (File input : configuration.resolve()) {
|
||||
JsonObject jsonObject = ModProcessor.readInstallerJson(input, project);
|
||||
for (Dependency dependency : configuration.getAllDependencies()) {
|
||||
for (File input : configuration.files(dependency)) {
|
||||
JsonObject jsonObject = ModProcessor.readInstallerJson(input, project);
|
||||
|
||||
if (jsonObject != null) {
|
||||
if (extension.getInstallerJson() != null) {
|
||||
project.getLogger().info("Found another installer JSON in, ignoring it! " + input);
|
||||
continue;
|
||||
if (jsonObject != null) {
|
||||
if (extension.getInstallerData() != null) {
|
||||
project.getLogger().info("Found another installer JSON in, ignoring it! " + input);
|
||||
continue;
|
||||
}
|
||||
|
||||
project.getLogger().info("Found installer JSON in " + input);
|
||||
extension.setInstallerData(new InstallerData(dependency.getVersion(), jsonObject));
|
||||
handleInstallerJson(jsonObject, project);
|
||||
}
|
||||
|
||||
project.getLogger().info("Found installer JSON in " + input);
|
||||
extension.setInstallerJson(jsonObject);
|
||||
handleInstallerJson(extension.getInstallerJson(), project);
|
||||
}
|
||||
}
|
||||
|
||||
if (extension.getInstallerJson() == null) {
|
||||
if (extension.getInstallerData() == null) {
|
||||
project.getLogger().warn("fabric-installer.json not found in classpath!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ public class RunConfig {
|
||||
|
||||
if (extension.getLoaderLaunchMethod().equals("launchwrapper")) {
|
||||
// if installer.json found...
|
||||
JsonObject installerJson = extension.getInstallerJson();
|
||||
JsonObject installerJson = extension.getInstallerData().installerJson();
|
||||
|
||||
if (installerJson != null) {
|
||||
List<String> sideKeys = ImmutableList.of(environment, "common");
|
||||
@@ -306,7 +306,7 @@ public class RunConfig {
|
||||
}
|
||||
|
||||
private static String getMainClass(String side, LoomGradleExtension extension, String defaultMainClass) {
|
||||
JsonObject installerJson = extension.getInstallerJson();
|
||||
JsonObject installerJson = extension.getInstallerData().installerJson();
|
||||
|
||||
if (installerJson != null && installerJson.has("mainClass")) {
|
||||
JsonElement mainClassJson = installerJson.get("mainClass");
|
||||
|
||||
@@ -27,6 +27,8 @@ package net.fabricmc.loom.task;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -43,6 +45,8 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
@@ -70,6 +74,8 @@ import org.gradle.jvm.tasks.Jar;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.zeroturnaround.zip.ZipUtil;
|
||||
import org.zeroturnaround.zip.transform.StreamZipEntryTransformer;
|
||||
import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.build.JarRemapper;
|
||||
@@ -80,6 +86,7 @@ import net.fabricmc.loom.build.nesting.MergedNestedJarProvider;
|
||||
import net.fabricmc.loom.build.nesting.NestedDependencyProvider;
|
||||
import net.fabricmc.loom.build.nesting.NestedJarPathProvider;
|
||||
import net.fabricmc.loom.build.nesting.NestedJarProvider;
|
||||
import net.fabricmc.loom.configuration.JarManifestConfiguration;
|
||||
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
@@ -94,6 +101,8 @@ import net.fabricmc.mapping.tree.TinyTree;
|
||||
import net.fabricmc.stitch.util.Pair;
|
||||
|
||||
public class RemapJarTask extends Jar {
|
||||
private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF";
|
||||
|
||||
private final RegularFileProperty input;
|
||||
private final Property<Boolean> addNestedDependencies;
|
||||
private final Property<Boolean> addDefaultNestedDependencies;
|
||||
@@ -284,6 +293,25 @@ public class RemapJarTask extends Jar {
|
||||
Preconditions.checkArgument(replaced, "Failed to remap access widener");
|
||||
}
|
||||
|
||||
if (!extension.isForge()) {
|
||||
// Add data to the manifest
|
||||
boolean transformed = ZipUtil.transformEntries(data.output.toFile(), new ZipEntryTransformerEntry[] {
|
||||
new ZipEntryTransformerEntry(MANIFEST_PATH, new StreamZipEntryTransformer() {
|
||||
@Override
|
||||
protected void transform(ZipEntry zipEntry, InputStream in, OutputStream out) throws IOException {
|
||||
Manifest manifest = new Manifest(in);
|
||||
JarManifestConfiguration manifestConfiguration = new JarManifestConfiguration(project);
|
||||
|
||||
manifestConfiguration.configure(manifest);
|
||||
manifest.getMainAttributes().putValue("Fabric-Mapping-Namespace", toM);
|
||||
|
||||
manifest.write(out);
|
||||
}
|
||||
})
|
||||
});
|
||||
Preconditions.checkArgument(transformed, "Failed to transform jar manifest");
|
||||
}
|
||||
|
||||
if (isReproducibleFileOrder() || !isPreserveFileTimestamps()) {
|
||||
try {
|
||||
ZipReprocessorUtil.reprocessZip(output.toFile(), isReproducibleFileOrder(), isPreserveFileTimestamps());
|
||||
|
||||
@@ -30,7 +30,9 @@ import com.google.common.io.Files
|
||||
import net.fabricmc.loom.test.util.ProjectTestTrait
|
||||
import spock.lang.Specification
|
||||
import spock.lang.Unroll
|
||||
import spock.util.environment.RestoreSystemProperties
|
||||
|
||||
import static java.lang.System.setProperty
|
||||
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
|
||||
|
||||
class ReproducibleBuildTest extends Specification implements ProjectTestTrait {
|
||||
@@ -39,18 +41,20 @@ class ReproducibleBuildTest extends Specification implements ProjectTestTrait {
|
||||
"reproducible"
|
||||
}
|
||||
|
||||
@RestoreSystemProperties
|
||||
@Unroll
|
||||
def "build (gradle #gradle)"() {
|
||||
when:
|
||||
setProperty('loom.test.reproducible', 'true')
|
||||
def result = create("build", gradle)
|
||||
then:
|
||||
result.task(":build").outcome == SUCCESS
|
||||
getOutputHash("fabric-example-mod-1.0.0.jar") == modHash
|
||||
getOutputHash("fabric-example-mod-1.0.0-sources.jar") in sourceHash // Done for different line endings.
|
||||
where:
|
||||
gradle | modHash | sourceHash
|
||||
'6.8.3' | "6132ffb4117adb7e258f663110552952" | ["be31766e6cafbe4ae3bca9e35ba63169", "7348b0bd87d36d7ec6f3bca9c2b66062"]
|
||||
'7.0-rc-1' | "6132ffb4117adb7e258f663110552952" | ["be31766e6cafbe4ae3bca9e35ba63169", "7348b0bd87d36d7ec6f3bca9c2b66062"]
|
||||
gradle | modHash | sourceHash
|
||||
DEFAULT_GRADLE | "ed3306ef60f434c55048cba8de5dab95" | ["be31766e6cafbe4ae3bca9e35ba63169", "7348b0bd87d36d7ec6f3bca9c2b66062"]
|
||||
PRE_RELEASE_GRADLE | "ed3306ef60f434c55048cba8de5dab95" | ["be31766e6cafbe4ae3bca9e35ba63169", "7348b0bd87d36d7ec6f3bca9c2b66062"]
|
||||
}
|
||||
|
||||
String getOutputHash(String name) {
|
||||
|
||||
@@ -24,13 +24,14 @@
|
||||
|
||||
package net.fabricmc.loom.test.integration
|
||||
|
||||
import net.fabricmc.loom.test.util.ArchiveAssertionsTrait
|
||||
import net.fabricmc.loom.test.util.ProjectTestTrait
|
||||
import spock.lang.Specification
|
||||
import spock.lang.Unroll
|
||||
|
||||
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
|
||||
|
||||
class SimpleProjectTest extends Specification implements ProjectTestTrait {
|
||||
class SimpleProjectTest extends Specification implements ProjectTestTrait, ArchiveAssertionsTrait {
|
||||
@Override
|
||||
String name() {
|
||||
"simple"
|
||||
@@ -42,6 +43,7 @@ class SimpleProjectTest extends Specification implements ProjectTestTrait {
|
||||
def result = create("build", gradle)
|
||||
then:
|
||||
result.task(":build").outcome == SUCCESS
|
||||
getArchiveEntry("fabric-example-mod-1.0.0.jar", "META-INF/MANIFEST.MF").contains("Fabric-Loom-Version: 0.0.0+unknown")
|
||||
where:
|
||||
gradle | _
|
||||
DEFAULT_GRADLE | _
|
||||
|
||||
Reference in New Issue
Block a user