From 66f92547045392abc7cf3d43927344bd560fbfd4 Mon Sep 17 00:00:00 2001 From: Geoff Bourne Date: Sat, 4 Oct 2025 16:16:56 -0500 Subject: [PATCH] paper: now applies channel and resolves stable by default --- dev/paper.http | 9 +- .../helpers/paper/InstallPaperCommand.java | 21 +- .../helpers/paper/PaperDownloadsClient.java | 62 +++-- .../itzg/helpers/paper/RequestedChannel.java | 17 +- .../paper/PaperDownloadsClientTest.java | 52 +++- ...n => projects_paper_1_21_6_builds_46.json} | 0 .../v3/projects_paper_1_21_8_builds_60.json | 22 ++ .../projects_paper_1_21_9-rc1_builds_36.json | 22 ++ .../v3/projects_paper_1_21_9_builds_49.json | 22 ++ .../projects_paper_versions_with_alphas.json | 261 ++++++++++++++++++ 10 files changed, 444 insertions(+), 44 deletions(-) rename src/test/resources/__files/paper/v3/{response_paper_build_response.json => projects_paper_1_21_6_builds_46.json} (100%) create mode 100644 src/test/resources/__files/paper/v3/projects_paper_1_21_8_builds_60.json create mode 100644 src/test/resources/__files/paper/v3/projects_paper_1_21_9-rc1_builds_36.json create mode 100644 src/test/resources/__files/paper/v3/projects_paper_1_21_9_builds_49.json create mode 100644 src/test/resources/__files/paper/v3/projects_paper_versions_with_alphas.json diff --git a/dev/paper.http b/dev/paper.http index 294afce9..7bbc36e7 100644 --- a/dev/paper.http +++ b/dev/paper.http @@ -1,2 +1,9 @@ +@project =paper +@version =1.21.9 +@build =49 + ### -GET https://api.papermc.io/v2/projects/paper \ No newline at end of file +GET https://fill.papermc.io/v3/projects/paper/versions + +### +GET https://fill.papermc.io/v3/projects/{{project}}/versions/{{version}}/builds/{{build}} diff --git a/src/main/java/me/itzg/helpers/paper/InstallPaperCommand.java b/src/main/java/me/itzg/helpers/paper/InstallPaperCommand.java index ad604e32..0e9a334e 100644 --- a/src/main/java/me/itzg/helpers/paper/InstallPaperCommand.java +++ b/src/main/java/me/itzg/helpers/paper/InstallPaperCommand.java @@ -120,12 +120,14 @@ public Integer call() throws Exception { else { if (requestCheckUpdates) { return checkForUpdates(client, oldManifest, - inputs.coordinates.project, inputs.coordinates.version, inputs.coordinates.build + inputs.coordinates.project, inputs.coordinates.version, inputs.coordinates.build, + inputs.coordinates.channel ); } result = downloadUsingCoordinates(client, inputs.coordinates.project, - inputs.coordinates.version, inputs.coordinates.build + inputs.coordinates.version, inputs.coordinates.build, + inputs.coordinates.channel ) .block(); } @@ -151,7 +153,8 @@ public Integer call() throws Exception { } private Integer checkForUpdates(PaperDownloadsClient client, PaperManifest oldManifest, - String project, String version, Integer build + String project, String version, Integer build, + RequestedChannel channel ) { if (oldManifest != null && oldManifest.getCustomDownloadUrl() != null) { log.info("Using custom download URL before"); @@ -184,7 +187,7 @@ private Integer checkForUpdates(PaperDownloadsClient client, PaperManifest oldMa } } else { - return client.getLatestVersionBuild(project) + return client.getLatestVersionBuild(project, channel) .map(versionBuild -> { if (oldManifest == null) { return logVersion(project, versionBuild.getVersion(), versionBuild.getBuild()); @@ -223,10 +226,11 @@ private static boolean mismatchingVersions(PaperManifest oldManifest, String pro } private Mono downloadUsingCoordinates(PaperDownloadsClient client, String project, - String version, Integer build + String version, Integer build, + RequestedChannel channel ) { return - assembleDownload(client, project, version, build) + assembleDownload(client, project, version, build, channel) .map(result -> Result.builder() .newManifest( @@ -244,7 +248,8 @@ private Mono downloadUsingCoordinates(PaperDownloadsClient client, Strin } private Mono assembleDownload(PaperDownloadsClient client, String project, String version, - Integer build + Integer build, + RequestedChannel channel ) { final FileDownloadStatusHandler downloadStatusHandler = Fetch.loggingDownloadStatusHandler(log); @@ -257,7 +262,7 @@ private Mono assembleDownload(PaperDownloadsClient client, Str } } else { - return client.downloadLatest(project, outputDirectory, downloadStatusHandler); + return client.downloadLatest(project, channel, outputDirectory, downloadStatusHandler); } } diff --git a/src/main/java/me/itzg/helpers/paper/PaperDownloadsClient.java b/src/main/java/me/itzg/helpers/paper/PaperDownloadsClient.java index 65673dc2..4ae48a78 100644 --- a/src/main/java/me/itzg/helpers/paper/PaperDownloadsClient.java +++ b/src/main/java/me/itzg/helpers/paper/PaperDownloadsClient.java @@ -3,6 +3,7 @@ import java.net.URI; import java.nio.file.Path; import lombok.Data; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import me.itzg.helpers.errors.GenericException; import me.itzg.helpers.errors.InvalidParameterException; @@ -12,10 +13,11 @@ import me.itzg.helpers.http.SharedFetch; import me.itzg.helpers.http.UriBuilder; import me.itzg.helpers.paper.model.BuildResponse; +import me.itzg.helpers.paper.model.Channel; import me.itzg.helpers.paper.model.Download; import me.itzg.helpers.paper.model.ProjectResponse; -import me.itzg.helpers.paper.model.Version; import me.itzg.helpers.paper.model.VersionResponse; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; /** @@ -45,10 +47,10 @@ public static class VersionBuildFile { final Path file; } - public Mono getLatestVersionBuild(String project) { + public Mono getLatestVersionBuild(String project, RequestedChannel requestedChannel) { return getProjectVersions(project) .flatMap(projectResponse -> - extractVersionBuild(project, projectResponse) + extractLatestVersionBuild(project, requestedChannel, projectResponse) ); } @@ -68,12 +70,12 @@ public Mono getLatestBuild(String project, String version) { .map(BuildResponse::getId); } - public Mono downloadLatest(String project, + public Mono downloadLatest(String project, RequestedChannel requestedChannel, Path outputDirectory, FileDownloadStatusHandler downloadStatusHandler ) { return getProjectVersions(project) .flatMap(projectResponse -> - extractVersionBuild(project, projectResponse) + extractLatestVersionBuild(project, requestedChannel, projectResponse) .flatMap(versionBuild -> download(project, outputDirectory, downloadStatusHandler, versionBuild.getVersion(), @@ -111,6 +113,15 @@ public Mono download(String project, String version, int build ) { + return getBuild(project, version, build) + .flatMap(buildResponse -> + downloadWithBuildResponse(outputDirectory, downloadStatusHandler, version, buildResponse) + .map(path -> new VersionBuildFile(version, build, path)) + ); + } + + private Mono getBuild(String project, String version, int build) { + return sharedFetch.fetch( uriBuilder.resolve("/v3/projects/{project}/versions/{version}/builds/{build}", project, version, build @@ -122,10 +133,6 @@ public Mono download(String project, FailedRequestException::isNotFound, throwable -> new InvalidParameterException( String.format("Requested version %s, build %d is not available", version, build)) - ) - .flatMap(buildResponse -> - downloadWithBuildResponse(outputDirectory, downloadStatusHandler, version, buildResponse) - .map(path -> new VersionBuildFile(version, build, path)) ); } @@ -142,26 +149,37 @@ private Mono getProjectVersions(String project) { ); } - private Mono extractVersionBuild(String project, ProjectResponse projectResponse) { + @RequiredArgsConstructor + private static class VersionAndBuildResponse { + final VersionResponse versionResponse; + final BuildResponse buildResponse; + } + + private Mono extractLatestVersionBuild(String project, RequestedChannel requestedChannel, ProjectResponse projectResponse) { if (projectResponse.getVersions() == null || projectResponse.getVersions().isEmpty()) { log.warn("No versions found for project={}", project); return Mono.error(() -> new InvalidParameterException("No versions found for project")); } - final VersionResponse versionResponse = projectResponse.getVersions().get(0); - final Version version = versionResponse.getVersion(); - if (versionResponse.getBuilds() == null || - versionResponse.getBuilds().isEmpty()) { - log.warn("No builds found for project={} version={}", project, version.getId()); - return Mono.error(() -> new InvalidParameterException( - String.format("No builds found for project version %s", version.getId())) - ); - } + return Flux.fromIterable(projectResponse.getVersions()) + .filter(versionResponse -> versionResponse.getBuilds() != null && !versionResponse.getBuilds().isEmpty()) + .concatMap(versionResponse -> + getBuild(project, versionResponse.getVersion().getId(), versionResponse.getBuilds().get(0)) + .map(buildResponse -> new VersionAndBuildResponse(versionResponse, buildResponse)) + ) + .takeUntil(vAndB -> acceptableChannel(vAndB.buildResponse.getChannel(), requestedChannel)) + .last() + .map(vAndB -> new VersionBuild(vAndB.versionResponse.getVersion().getId(), vAndB.buildResponse.getId())); + } - return Mono.just( - new VersionBuild(version.getId(), versionResponse.getBuilds().get(0)) - ); + private boolean acceptableChannel(Channel channel, RequestedChannel requestedChannel) { + for (final Channel mapped : requestedChannel.getMappedTo()) { + if (mapped.equals(channel)) { + return true; + } + } + return false; } private Mono downloadWithBuildResponse(Path outputDirectory, FileDownloadStatusHandler downloadStatusHandler, diff --git a/src/main/java/me/itzg/helpers/paper/RequestedChannel.java b/src/main/java/me/itzg/helpers/paper/RequestedChannel.java index 65016424..cf213278 100644 --- a/src/main/java/me/itzg/helpers/paper/RequestedChannel.java +++ b/src/main/java/me/itzg/helpers/paper/RequestedChannel.java @@ -1,6 +1,19 @@ package me.itzg.helpers.paper; +import lombok.Getter; +import lombok.ToString; +import me.itzg.helpers.paper.model.Channel; + +@ToString +@Getter public enum RequestedChannel { - DEFAULT, - EXPERIMENTAL + DEFAULT(Channel.STABLE, Channel.RECOMMENDED), + EXPERIMENTAL(Channel.ALPHA, Channel.BETA), + ALPHA(Channel.ALPHA); + + private final Channel[] mappedTo; + + RequestedChannel(Channel... mappedTo) { + this.mappedTo = mappedTo; + } } diff --git a/src/test/java/me/itzg/helpers/paper/PaperDownloadsClientTest.java b/src/test/java/me/itzg/helpers/paper/PaperDownloadsClientTest.java index 2149ca83..9ee138ed 100644 --- a/src/test/java/me/itzg/helpers/paper/PaperDownloadsClientTest.java +++ b/src/test/java/me/itzg/helpers/paper/PaperDownloadsClientTest.java @@ -7,36 +7,66 @@ import com.github.tomakehurst.wiremock.junit5.WireMockTest; import java.net.URI; import java.nio.file.Path; +import java.util.stream.Stream; import me.itzg.helpers.http.FileDownloadStatusHandler; import me.itzg.helpers.http.SharedFetch.Options; import me.itzg.helpers.paper.PaperDownloadsClient.VersionBuild; import me.itzg.helpers.paper.PaperDownloadsClient.VersionBuildFile; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Mockito; @WireMockTest class PaperDownloadsClientTest { - @Test - void latestVersionBuild(WireMockRuntimeInfo wmInfo) { + public static Stream latestVersionBuild_args() { + return Stream.of( + Arguments.arguments(RequestedChannel.DEFAULT, "1.21.8", 60), + Arguments.arguments(RequestedChannel.EXPERIMENTAL, "1.21.9", 49) + ); + } + + @ParameterizedTest + @MethodSource("latestVersionBuild_args") + void latestVersionBuild(RequestedChannel requestedChannel, String expectedVersion, int expectedBuild, WireMockRuntimeInfo wmInfo) { //TODO use urlPathTemplate with Wiremock 3.x stubFor(get(urlPathEqualTo("/v3/projects/paper/versions")) .willReturn(aResponse() .withHeader("Content-Type", "application/json") - .withBodyFile("paper/v3/response_paper_project.json") + .withBodyFile("paper/v3/projects_paper_versions_with_alphas.json") + ) + ); + stubFor(get(urlPathEqualTo("/v3/projects/paper/versions/1.21.9/builds/49")) + .willReturn(aResponse() + .withHeader("Content-Type", "application/json") + .withBodyFile("paper/v3/projects_paper_1_21_9_builds_49.json") + ) + ); + stubFor(get(urlPathEqualTo("/v3/projects/paper/versions/1.21.9-rc1/builds/36")) + .willReturn(aResponse() + .withHeader("Content-Type", "application/json") + .withBodyFile("paper/v3/projects_paper_1_21_9-rc1_builds_36.json") + ) + ); + stubFor(get(urlPathEqualTo("/v3/projects/paper/versions/1.21.8/builds/60")) + .willReturn(aResponse() + .withHeader("Content-Type", "application/json") + .withBodyFile("paper/v3/projects_paper_1_21_8_builds_60.json") ) ); try (PaperDownloadsClient client = new PaperDownloadsClient(wmInfo.getHttpBaseUrl(), Options.builder().build() )) { - final VersionBuild result = client.getLatestVersionBuild("paper") + final VersionBuild result = client.getLatestVersionBuild("paper", requestedChannel) .block(); assertThat(result).isNotNull(); - assertThat(result.getVersion()).isEqualTo("1.21.6"); - assertThat(result.getBuild()).isEqualTo(46); + assertThat(result.getVersion()).isEqualTo(expectedVersion); + assertThat(result.getBuild()).isEqualTo(expectedBuild); } } @@ -46,7 +76,7 @@ void latestBuild(WireMockRuntimeInfo wmInfo) { stubFor(get(urlPathEqualTo("/v3/projects/paper/versions/1.21.6/builds/latest")) .willReturn(aResponse() .withHeader("Content-Type", "application/json") - .withBodyFile("paper/v3/response_paper_build_response.json") + .withBodyFile("paper/v3/projects_paper_1_21_6_builds_46.json") ) ); @@ -66,7 +96,7 @@ void downloadsSpecific(WireMockRuntimeInfo wmInfo, @TempDir Path tempDir) { stubFor(get(urlPathEqualTo("/v3/projects/paper/versions/1.21.6/builds/46")) .willReturn(aResponse() .withHeader("Content-Type", "application/json") - .withBodyFile("paper/v3/response_paper_build_response.json") + .withBodyFile("paper/v3/projects_paper_1_21_6_builds_46.json") ) ); @@ -112,7 +142,7 @@ void downloadsLatest(WireMockRuntimeInfo wmInfo, @TempDir Path tempDir) { stubFor(get(urlPathEqualTo("/v3/projects/paper/versions/1.21.6/builds/46")) .willReturn(aResponse() .withHeader("Content-Type", "application/json") - .withBodyFile("paper/v3/response_paper_build_response.json") + .withBodyFile("paper/v3/projects_paper_1_21_6_builds_46.json") ) ); stubFor(get(urlPathEqualTo("/v1/objects/bfca155b4a6b45644bfc1766f4e02a83c736e45fcc060e8788c71d6e7b3d56f6/paper-1.21.6-46.jar")) @@ -129,7 +159,7 @@ void downloadsLatest(WireMockRuntimeInfo wmInfo, @TempDir Path tempDir) { .filesViaUrl(URI.create(wmInfo.getHttpBaseUrl())) .build() )) { - final VersionBuildFile result = client.downloadLatest("paper", tempDir, statusHandler) + final VersionBuildFile result = client.downloadLatest("paper", RequestedChannel.DEFAULT, tempDir, statusHandler) .block(); assertThat(result).isNotNull(); @@ -151,7 +181,7 @@ void downloadsLatestBuild(WireMockRuntimeInfo wmInfo, @TempDir Path tempDir) { stubFor(get(urlPathEqualTo("/v3/projects/paper/versions/1.21.6/builds/latest")) .willReturn(aResponse() .withHeader("Content-Type", "application/json") - .withBodyFile("paper/v3/response_paper_build_response.json") + .withBodyFile("paper/v3/projects_paper_1_21_6_builds_46.json") ) ); stubFor(get(urlPathEqualTo("/v1/objects/bfca155b4a6b45644bfc1766f4e02a83c736e45fcc060e8788c71d6e7b3d56f6/paper-1.21.6-46.jar")) diff --git a/src/test/resources/__files/paper/v3/response_paper_build_response.json b/src/test/resources/__files/paper/v3/projects_paper_1_21_6_builds_46.json similarity index 100% rename from src/test/resources/__files/paper/v3/response_paper_build_response.json rename to src/test/resources/__files/paper/v3/projects_paper_1_21_6_builds_46.json diff --git a/src/test/resources/__files/paper/v3/projects_paper_1_21_8_builds_60.json b/src/test/resources/__files/paper/v3/projects_paper_1_21_8_builds_60.json new file mode 100644 index 00000000..d69ac20c --- /dev/null +++ b/src/test/resources/__files/paper/v3/projects_paper_1_21_8_builds_60.json @@ -0,0 +1,22 @@ +{ + "id": 60, + "time": "2025-09-06T21:50:11.982Z", + "channel": "STABLE", + "commits": [ + { + "sha": "29c8822d90899c89d2689338e81a98f690bcba12", + "time": "2025-09-06T21:38:29Z", + "message": "Remove no longer needed MC-210802 fix (#13059)\n\n" + } + ], + "downloads": { + "server:default": { + "name": "paper-1.21.8-60.jar", + "checksums": { + "sha256": "8de7c52c3b02403503d16fac58003f1efef7dd7a0256786843927fa92ee57f1e" + }, + "size": 52811717, + "url": "https://fill-data.papermc.io/v1/objects/8de7c52c3b02403503d16fac58003f1efef7dd7a0256786843927fa92ee57f1e/paper-1.21.8-60.jar" + } + } +} \ No newline at end of file diff --git a/src/test/resources/__files/paper/v3/projects_paper_1_21_9-rc1_builds_36.json b/src/test/resources/__files/paper/v3/projects_paper_1_21_9-rc1_builds_36.json new file mode 100644 index 00000000..42690426 --- /dev/null +++ b/src/test/resources/__files/paper/v3/projects_paper_1_21_9-rc1_builds_36.json @@ -0,0 +1,22 @@ +{ + "id": 36, + "time": "2025-09-30T13:38:40.064Z", + "channel": "ALPHA", + "commits": [ + { + "sha": "5b6165c48d64b4daa44ac5f498bc11ee928e4637", + "time": "2025-09-30T13:26:15Z", + "message": "Add spawnreason for building copper golems (#13112)\n\n" + } + ], + "downloads": { + "server:default": { + "name": "paper-1.21.9-rc1-36.jar", + "checksums": { + "sha256": "f737c4ce0afd8ca897c5330188634859148419c6c2d2e172c65f581c47430ab1" + }, + "size": 52515036, + "url": "https://fill-data.papermc.io/v1/objects/f737c4ce0afd8ca897c5330188634859148419c6c2d2e172c65f581c47430ab1/paper-1.21.9-rc1-36.jar" + } + } +} \ No newline at end of file diff --git a/src/test/resources/__files/paper/v3/projects_paper_1_21_9_builds_49.json b/src/test/resources/__files/paper/v3/projects_paper_1_21_9_builds_49.json new file mode 100644 index 00000000..c7ceccd8 --- /dev/null +++ b/src/test/resources/__files/paper/v3/projects_paper_1_21_9_builds_49.json @@ -0,0 +1,22 @@ +{ + "id": 49, + "time": "2025-10-04T18:54:19.646Z", + "channel": "ALPHA", + "commits": [ + { + "sha": "a4a7461cefdeaa6d230c411e54ae0c26a5a942e3", + "time": "2025-10-04T18:41:00Z", + "message": "Rebase fixups\n\nOops\n" + } + ], + "downloads": { + "server:default": { + "name": "paper-1.21.9-49.jar", + "checksums": { + "sha256": "4cac1132df2c0998cdcd150a7b201acfea55ebe60b3325d388597934aa2bb1c7" + }, + "size": 52528557, + "url": "https://fill-data.papermc.io/v1/objects/4cac1132df2c0998cdcd150a7b201acfea55ebe60b3325d388597934aa2bb1c7/paper-1.21.9-49.jar" + } + } +} \ No newline at end of file diff --git a/src/test/resources/__files/paper/v3/projects_paper_versions_with_alphas.json b/src/test/resources/__files/paper/v3/projects_paper_versions_with_alphas.json new file mode 100644 index 00000000..e7a347dd --- /dev/null +++ b/src/test/resources/__files/paper/v3/projects_paper_versions_with_alphas.json @@ -0,0 +1,261 @@ +{ + "versions": [ + { + "version": { + "id": "1.21.9", + "support": { + "status": "SUPPORTED" + }, + "java": { + "version": { + "minimum": 21 + }, + "flags": { + "recommended": [ + "-XX:+AlwaysPreTouch", + "-XX:+DisableExplicitGC", + "-XX:+ParallelRefProcEnabled", + "-XX:+PerfDisableSharedMem", + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseG1GC", + "-XX:G1HeapRegionSize=8M", + "-XX:G1HeapWastePercent=5", + "-XX:G1MaxNewSizePercent=40", + "-XX:G1MixedGCCountTarget=4", + "-XX:G1MixedGCLiveThresholdPercent=90", + "-XX:G1NewSizePercent=30", + "-XX:G1RSetUpdatingPauseTimePercent=5", + "-XX:G1ReservePercent=20", + "-XX:InitiatingHeapOccupancyPercent=15", + "-XX:MaxGCPauseMillis=200", + "-XX:MaxTenuringThreshold=1", + "-XX:SurvivorRatio=32" + ] + } + } + }, + "builds": [ + 49, + 48, + 47, + 46, + 45, + 44, + 42, + 41, + 40, + 38, + 37 + ] + }, + { + "version": { + "id": "1.21.9-rc1", + "support": { + "status": "UNSUPPORTED", + "end": "2025-09-29" + }, + "java": { + "version": { + "minimum": 21 + }, + "flags": { + "recommended": [ + "-XX:+AlwaysPreTouch", + "-XX:+DisableExplicitGC", + "-XX:+ParallelRefProcEnabled", + "-XX:+PerfDisableSharedMem", + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseG1GC", + "-XX:G1HeapRegionSize=8M", + "-XX:G1HeapWastePercent=5", + "-XX:G1MaxNewSizePercent=40", + "-XX:G1MixedGCCountTarget=4", + "-XX:G1MixedGCLiveThresholdPercent=90", + "-XX:G1NewSizePercent=30", + "-XX:G1RSetUpdatingPauseTimePercent=5", + "-XX:G1ReservePercent=20", + "-XX:InitiatingHeapOccupancyPercent=15", + "-XX:MaxGCPauseMillis=200", + "-XX:MaxTenuringThreshold=1", + "-XX:SurvivorRatio=32" + ] + } + } + }, + "builds": [ + 36, + 35, + 34, + 33, + 32, + 30, + 29, + 28, + 27, + 26, + 25, + 24, + 23 + ] + }, + { + "version": { + "id": "1.21.8", + "support": { + "status": "SUPPORTED" + }, + "java": { + "version": { + "minimum": 21 + }, + "flags": { + "recommended": [ + "-XX:+AlwaysPreTouch", + "-XX:+DisableExplicitGC", + "-XX:+ParallelRefProcEnabled", + "-XX:+PerfDisableSharedMem", + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseG1GC", + "-XX:G1HeapRegionSize=8M", + "-XX:G1HeapWastePercent=5", + "-XX:G1MaxNewSizePercent=40", + "-XX:G1MixedGCCountTarget=4", + "-XX:G1MixedGCLiveThresholdPercent=90", + "-XX:G1NewSizePercent=30", + "-XX:G1RSetUpdatingPauseTimePercent=5", + "-XX:G1ReservePercent=20", + "-XX:InitiatingHeapOccupancyPercent=15", + "-XX:MaxGCPauseMillis=200", + "-XX:MaxTenuringThreshold=1", + "-XX:SurvivorRatio=32" + ] + } + } + }, + "builds": [ + 60, + 59, + 58, + 57, + 56, + 55, + 54, + 53, + 51, + 50, + 49, + 48, + 47, + 46, + 45, + 44, + 43, + 42, + 40, + 39, + 36, + 35, + 34, + 33, + 32, + 31, + 30, + 29, + 28, + 27, + 26, + 25, + 24, + 23, + 22, + 21, + 20, + 19, + 18, + 17, + 16, + 15, + 14, + 12, + 11, + 10, + 9, + 8, + 7, + 6, + 5, + 4, + 3, + 2, + 1 + ] + }, + { + "version": { + "id": "1.21.7", + "support": { + "status": "UNSUPPORTED", + "end": "2025-07-17" + }, + "java": { + "version": { + "minimum": 21 + }, + "flags": { + "recommended": [ + "-XX:+AlwaysPreTouch", + "-XX:+DisableExplicitGC", + "-XX:+ParallelRefProcEnabled", + "-XX:+PerfDisableSharedMem", + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseG1GC", + "-XX:G1HeapRegionSize=8M", + "-XX:G1HeapWastePercent=5", + "-XX:G1MaxNewSizePercent=40", + "-XX:G1MixedGCCountTarget=4", + "-XX:G1MixedGCLiveThresholdPercent=90", + "-XX:G1NewSizePercent=30", + "-XX:G1RSetUpdatingPauseTimePercent=5", + "-XX:G1ReservePercent=20", + "-XX:InitiatingHeapOccupancyPercent=15", + "-XX:MaxGCPauseMillis=200", + "-XX:MaxTenuringThreshold=1", + "-XX:SurvivorRatio=32" + ] + } + } + }, + "builds": [ + 32, + 31, + 30, + 29, + 28, + 27, + 26, + 25, + 24, + 23, + 22, + 21, + 20, + 18, + 17, + 16, + 15, + 14, + 13, + 12, + 10, + 9, + 8, + 6, + 5, + 4, + 3, + 2 + ] + } + ] +} \ No newline at end of file