From d844d667511a91743244967b751ae67971b6a957 Mon Sep 17 00:00:00 2001 From: fireph <443370+fireph@users.noreply.github.com> Date: Wed, 18 Jun 2025 17:12:04 -0700 Subject: [PATCH 1/4] Add Modrinth project files support Uses the same syntax as curseforge (@/path/to/modrinth-mods.txt) --- .../helpers/modrinth/ModrinthCommand.java | 38 +++++++++++++++++-- .../helpers/modrinth/ModrinthCommandTest.java | 33 ++++++++++++++++ 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/src/main/java/me/itzg/helpers/modrinth/ModrinthCommand.java b/src/main/java/me/itzg/helpers/modrinth/ModrinthCommand.java index 81119d81..7bc8e0b2 100644 --- a/src/main/java/me/itzg/helpers/modrinth/ModrinthCommand.java +++ b/src/main/java/me/itzg/helpers/modrinth/ModrinthCommand.java @@ -9,6 +9,7 @@ import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -46,10 +47,17 @@ public class ModrinthCommand implements Callable { @Option( names = "--projects", - description = "Project ID or Slug. Prefix with loader: e.g. fabric:project-id", + description = "Project ID or Slug. Can be |," + + " :|," + + " :|:," + + " '@'" + + "%nExamples: fabric-api, fabric:fabric-api, fabric:fabric-api:0.76.1+1.19.2," + + " datapack:terralith, @/path/to/modrinth-mods.txt" + + "%nValid release types: release, beta, alpha" + + "%nValid loaders: fabric, forge, paper, datapack, etc.", split = SPLIT_COMMA_NL, splitSynopsisLabel = SPLIT_SYNOPSIS_COMMA_NL, - paramLabel = "[loader:]id|slug" + paramLabel = "[loader:]id|slug[:version]" ) List projects; @@ -124,7 +132,7 @@ private List processProjects(List projects) { //noinspection DataFlowIssue since it thinks block() may return null return modrinthApiClient.bulkGetProjects( - projects.stream() + expandProjectListings(projects).stream() .filter(s -> !s.trim().isEmpty()) .map(ProjectRef::parse) ) @@ -142,6 +150,30 @@ private List processProjects(List projects) { } } + private List expandProjectListings(List projects) { + return projects.stream() + .distinct() + // handle @-file containing refs + .flatMap(ref -> { + if (ref.startsWith("@")) { + try { + return Files.readAllLines(Paths.get(ref.substring(1))).stream() + .map(s -> s + .replaceFirst("#.*", "") + .trim() + ) + .filter(s -> !s.isEmpty()); + } catch (IOException e) { + throw new GenericException("Reading project refs from file: " + ref.substring(1), e); + } + } + else { + return Stream.of(ref); + } + }) + .collect(Collectors.toList()); + } + private ModrinthManifest loadManifest() throws IOException { final Path legacyManifestPath = outputDirectory.resolve(LegacyModrinthManifest.FILENAME); diff --git a/src/test/java/me/itzg/helpers/modrinth/ModrinthCommandTest.java b/src/test/java/me/itzg/helpers/modrinth/ModrinthCommandTest.java index bc77a237..cd3d6e20 100644 --- a/src/test/java/me/itzg/helpers/modrinth/ModrinthCommandTest.java +++ b/src/test/java/me/itzg/helpers/modrinth/ModrinthCommandTest.java @@ -15,6 +15,8 @@ import com.github.tomakehurst.wiremock.junit5.WireMockExtension; import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder; import java.nio.file.Path; +import java.nio.file.Files; +import java.util.Arrays; import java.util.function.Consumer; import me.itzg.helpers.LatchingExecutionExceptionHandler; import me.itzg.helpers.errors.InvalidParameterException; @@ -378,6 +380,37 @@ void handlesDatapacksLatestVersion(@TempDir Path tempDir) { .hasContent("content of zip"); } + @Test + void usingListingFile(@TempDir Path tempDir) throws Exception { + setupStubs(); + + final Path listingFile = Files.write(tempDir.resolve("listing.txt"), + Arrays.asList( + "fabric-api:vNBWcMLP", + "# This is a comment", + "cloth-config:qA00xo1O", + "", + "# Another comment" + ) + ); + + final int exitCode = new CommandLine( + new ModrinthCommand() + ) + .execute( + "--api-base-url", wm.getRuntimeInfo().getHttpBaseUrl(), + "--output-directory", tempDir.toString(), + "--game-version", "1.21.5", + "--loader", "fabric", + "--projects", "@" + listingFile + ); + + assertThat(exitCode).isEqualTo(ExitCode.OK); + + assertThat(tempDir.resolve("mods/fabric-api-0.127.1+1.21.5.jar")).exists(); + assertThat(tempDir.resolve("mods/cloth-config-18.0.145-fabric.jar")).exists(); + } + @NotNull private static RequestPatternBuilder projectVersionsRequest(String projectId) { return getRequestedFor(urlPathEqualTo("/v2/project/" + projectId + "/version")); From 2b8aa8530641a65a747d43584747dc20d35abf46 Mon Sep 17 00:00:00 2001 From: fireph <443370+fireph@users.noreply.github.com> Date: Wed, 18 Jun 2025 17:59:44 -0700 Subject: [PATCH 2/4] use correct versions for stubs --- .../me/itzg/helpers/modrinth/ModrinthCommandTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/java/me/itzg/helpers/modrinth/ModrinthCommandTest.java b/src/test/java/me/itzg/helpers/modrinth/ModrinthCommandTest.java index cd3d6e20..bebc2109 100644 --- a/src/test/java/me/itzg/helpers/modrinth/ModrinthCommandTest.java +++ b/src/test/java/me/itzg/helpers/modrinth/ModrinthCommandTest.java @@ -386,9 +386,9 @@ void usingListingFile(@TempDir Path tempDir) throws Exception { final Path listingFile = Files.write(tempDir.resolve("listing.txt"), Arrays.asList( - "fabric-api:vNBWcMLP", + "fabric-api", "# This is a comment", - "cloth-config:qA00xo1O", + "cloth-config", "", "# Another comment" ) @@ -400,15 +400,15 @@ void usingListingFile(@TempDir Path tempDir) throws Exception { .execute( "--api-base-url", wm.getRuntimeInfo().getHttpBaseUrl(), "--output-directory", tempDir.toString(), - "--game-version", "1.21.5", + "--game-version", "1.19.2", "--loader", "fabric", "--projects", "@" + listingFile ); assertThat(exitCode).isEqualTo(ExitCode.OK); - assertThat(tempDir.resolve("mods/fabric-api-0.127.1+1.21.5.jar")).exists(); - assertThat(tempDir.resolve("mods/cloth-config-18.0.145-fabric.jar")).exists(); + assertThat(tempDir.resolve("mods/fabric-api-0.76.1+1.19.2.jar")).exists(); + assertThat(tempDir.resolve("mods/cloth-config-8.3.103-fabric.jar")).exists(); } @NotNull From d864398bba23c30518bb2c6613535621e167da9a Mon Sep 17 00:00:00 2001 From: fireph <443370+fireph@users.noreply.github.com> Date: Thu, 19 Jun 2025 14:33:16 -0700 Subject: [PATCH 3/4] fixed tests with missing .setExpandAtFiles(false) --- src/test/java/me/itzg/helpers/modrinth/ModrinthCommandTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/me/itzg/helpers/modrinth/ModrinthCommandTest.java b/src/test/java/me/itzg/helpers/modrinth/ModrinthCommandTest.java index bebc2109..829309b1 100644 --- a/src/test/java/me/itzg/helpers/modrinth/ModrinthCommandTest.java +++ b/src/test/java/me/itzg/helpers/modrinth/ModrinthCommandTest.java @@ -397,6 +397,7 @@ void usingListingFile(@TempDir Path tempDir) throws Exception { final int exitCode = new CommandLine( new ModrinthCommand() ) + .setExpandAtFiles(false) .execute( "--api-base-url", wm.getRuntimeInfo().getHttpBaseUrl(), "--output-directory", tempDir.toString(), From d6fc92e635f3f10d24d1f0e3064e9a5c29b86305 Mon Sep 17 00:00:00 2001 From: fireph <443370+fireph@users.noreply.github.com> Date: Fri, 20 Jun 2025 19:09:04 -0700 Subject: [PATCH 4/4] use "=" syntax for projects to avoid file expansion in ModrinthCommandTest --- .../java/me/itzg/helpers/modrinth/ModrinthCommandTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/me/itzg/helpers/modrinth/ModrinthCommandTest.java b/src/test/java/me/itzg/helpers/modrinth/ModrinthCommandTest.java index 829309b1..48ea9a08 100644 --- a/src/test/java/me/itzg/helpers/modrinth/ModrinthCommandTest.java +++ b/src/test/java/me/itzg/helpers/modrinth/ModrinthCommandTest.java @@ -397,13 +397,12 @@ void usingListingFile(@TempDir Path tempDir) throws Exception { final int exitCode = new CommandLine( new ModrinthCommand() ) - .setExpandAtFiles(false) .execute( "--api-base-url", wm.getRuntimeInfo().getHttpBaseUrl(), "--output-directory", tempDir.toString(), "--game-version", "1.19.2", "--loader", "fabric", - "--projects", "@" + listingFile + "--projects=@" + listingFile ); assertThat(exitCode).isEqualTo(ExitCode.OK);