diff --git a/docs/pages/platforms/curseforge.mdx b/docs/pages/platforms/curseforge.mdx index dcca942..0506867 100644 --- a/docs/pages/platforms/curseforge.mdx +++ b/docs/pages/platforms/curseforge.mdx @@ -74,6 +74,11 @@ publishMods { // Set a changelog using text, markdown, or html (defaults to markdown) changelog = "# Markdown changelog content" changelogType = "markdown" + + // Set the display name of an additional file + additionalFile(jar) { + name = "Fabric" + } } } ``` diff --git a/src/main/kotlin/me/modmuss50/mpp/platforms/curseforge/Curseforge.kt b/src/main/kotlin/me/modmuss50/mpp/platforms/curseforge/Curseforge.kt index 2004acd..b251895 100644 --- a/src/main/kotlin/me/modmuss50/mpp/platforms/curseforge/Curseforge.kt +++ b/src/main/kotlin/me/modmuss50/mpp/platforms/curseforge/Curseforge.kt @@ -17,13 +17,17 @@ import me.modmuss50.mpp.Validators import me.modmuss50.mpp.path import org.gradle.api.Action import org.gradle.api.JavaVersion +import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.logging.Logger import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.tasks.Input import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.Nested import org.gradle.api.tasks.Optional +import org.jetbrains.annotations.ApiStatus import javax.inject.Inject import kotlin.random.Random import kotlin.reflect.KClass @@ -57,6 +61,10 @@ interface CurseforgeOptions : PlatformOptions, PlatformOptionsInternal + @get:Nested + @get:ApiStatus.Internal + val additionalFilesExt: MapProperty + fun from(other: CurseforgeOptions) { super.from(other) fromDependencies(other) @@ -68,6 +76,7 @@ interface CurseforgeOptions : PlatformOptions, PlatformOptionsInternal) { @@ -93,6 +102,17 @@ interface CurseforgeOptions : PlatformOptions, PlatformOptionsInternal) { + val options = objectFactory.newInstance(AdditionalFileOptions::class.java) + action.execute(options) + + val fileCollection = objectFactory.fileCollection() + fileCollection.from(file) + + additionalFiles.from(fileCollection) + additionalFilesExt.put(fileCollection, options) + } + override fun setInternalDefaults() { apiEndpoint.convention("https://minecraft.curseforge.com") changelogType.convention("markdown") @@ -119,6 +139,17 @@ interface CurseforgeVersionRangeOptions { val end: Property } +/** + * Options for additional files to upload alongside the main file + */ +interface AdditionalFileOptions { + /** + * The display name of the additional file + */ + @get:Input + val name: Property +} + /** * Provides shorthand methods for adding dependencies to curseforge */ @@ -242,8 +273,13 @@ abstract class Curseforge @Inject constructor(name: String) : Platform(name), Cu api.uploadFile(projectId.get(), file.path, metadata) } + val additionalFileOptions = additionalFilesExt.get().map { (key, value) -> + key.singleFile.toPath() to value + }.toMap() + for (additionalFile in additionalFiles.files) { - val additionalMetadata = metadata.copy(parentFileID = response.id, gameVersions = null, displayName = null) + val fileOptions = additionalFileOptions[additionalFile.toPath()] + val additionalMetadata = metadata.copy(parentFileID = response.id, gameVersions = null, displayName = fileOptions?.name?.orNull) HttpUtils.retry(maxRetries.get(), "Failed to upload additional file") { api.uploadFile(projectId.get(), additionalFile.toPath(), additionalMetadata) diff --git a/src/test/kotlin/me/modmuss50/mpp/test/curseforge/CurseforgeTest.kt b/src/test/kotlin/me/modmuss50/mpp/test/curseforge/CurseforgeTest.kt index ddd9d73..c2fd545 100644 --- a/src/test/kotlin/me/modmuss50/mpp/test/curseforge/CurseforgeTest.kt +++ b/src/test/kotlin/me/modmuss50/mpp/test/curseforge/CurseforgeTest.kt @@ -348,4 +348,53 @@ class CurseforgeTest : IntegrationTest { assertEquals(TaskOutcome.FAILED, result.task(":publishCurseforge")!!.outcome) assertContains(result.output, "minecraftVersions contains duplicate values: [1.20.1]") } + + @Test + fun additionalFiles() { + val server = MockWebServer(MockCurseforgeApi()) + + val result = gradleTest() + .buildScript( + """ + val fabricJar = tasks.register("fabricJar", Jar::class.java) { + archiveClassifier = "fabric" + } + val forgeJar = tasks.register("forgeJar", Jar::class.java) { + archiveClassifier = "forge" + } + publishMods { + file = tasks.jar.flatMap { it.archiveFile } + changelog = "

Hello!

" + version = "1.0.0" + type = BETA + modLoaders.add("fabric") + + curseforge { + accessToken = "123" + projectId = "123456" + minecraftVersions.add("1.20.1") + + additionalFile(fabricJar.flatMap { it.archiveFile }) { + name = "Fabric" + } + + additionalFile(forgeJar.flatMap { it.archiveFile }) { + name = "Forge" + } + + apiEndpoint = "${server.endpoint}" + } + } + """.trimIndent(), + ) + .run("publishCurseforge") + server.close() + + val metadata = server.api.allMetadata + + assertEquals(TaskOutcome.SUCCESS, result.task(":publishCurseforge")!!.outcome) + assertEquals(3, metadata.size) + assertEquals("Fabric", metadata[1].displayName) + assertEquals("Forge", metadata[2].displayName) + } } diff --git a/src/test/kotlin/me/modmuss50/mpp/test/curseforge/MockCurseforgeApi.kt b/src/test/kotlin/me/modmuss50/mpp/test/curseforge/MockCurseforgeApi.kt index fda2451..76aebb2 100644 --- a/src/test/kotlin/me/modmuss50/mpp/test/curseforge/MockCurseforgeApi.kt +++ b/src/test/kotlin/me/modmuss50/mpp/test/curseforge/MockCurseforgeApi.kt @@ -18,6 +18,7 @@ class MockCurseforgeApi : MockWebServer.MockApi { @OptIn(ExperimentalSerializationApi::class) val json = Json { ignoreUnknownKeys = true; explicitNulls = false } var lastMetadata: CurseforgeApi.UploadFileMetadata? = null + var allMetadata: ArrayList = ArrayList() val files: ArrayList = ArrayList() override fun routes(): EndpointGroup { @@ -77,6 +78,7 @@ class MockCurseforgeApi : MockWebServer.MockApi { } lastMetadata = json.decodeFromString(metadata) + allMetadata.add(lastMetadata!!) files.add(file.filename()) context.result("""{"id": "20402"}""")