diff --git a/server/src/main/java/org/eclipse/openvsx/IExtensionRegistry.java b/server/src/main/java/org/eclipse/openvsx/IExtensionRegistry.java index 3f705fff1..e2d3428eb 100644 --- a/server/src/main/java/org/eclipse/openvsx/IExtensionRegistry.java +++ b/server/src/main/java/org/eclipse/openvsx/IExtensionRegistry.java @@ -11,6 +11,7 @@ import org.eclipse.openvsx.json.*; import org.eclipse.openvsx.search.ISearchService; +import org.eclipse.openvsx.util.BooleanTernary; import org.springframework.http.ResponseEntity; import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; @@ -27,7 +28,7 @@ public interface IExtensionRegistry { VersionsJson getVersions(String namespace, String extension, String targetPlatform, int size, int offset); - VersionReferencesJson getVersionReferences(String namespace, String extension, String targetPlatform, int size, int offset); + VersionReferencesJson getVersionReferences(String namespace, String extension, String targetPlatform, BooleanTernary preReleases, int size, int offset); ResponseEntity getFile(String namespace, String extensionName, String targetPlatform, String version, String fileName); diff --git a/server/src/main/java/org/eclipse/openvsx/LocalRegistryService.java b/server/src/main/java/org/eclipse/openvsx/LocalRegistryService.java index ebe3b45ab..11eb2dfe0 100644 --- a/server/src/main/java/org/eclipse/openvsx/LocalRegistryService.java +++ b/server/src/main/java/org/eclipse/openvsx/LocalRegistryService.java @@ -161,7 +161,7 @@ public VersionsJson getVersions(String namespace, String extension, String targe } @Override - public VersionReferencesJson getVersionReferences(String namespace, String extension, String targetPlatform, int size, int offset) { + public VersionReferencesJson getVersionReferences(String namespace, String extension, String targetPlatform, BooleanTernary preReleases, int size, int offset) { var pageRequest = PageRequest.of((offset/size), size); var page = targetPlatform == null ? repositories.findActiveVersionsSorted(namespace, extension, pageRequest) @@ -173,6 +173,11 @@ public VersionReferencesJson getVersionReferences(String namespace, String exten json.setOffset((int) page.getPageable().getOffset()); json.setTotalSize((int) page.getTotalElements()); json.setVersions(page.get() + .filter(extVersion -> switch (preReleases) { + case BooleanTernary.UNKNOWN -> true; + case BooleanTernary.TRUE -> extVersion.isPreRelease(); + case BooleanTernary.FALSE -> !extVersion.isPreRelease(); + }) .map(extVersion -> { var versionRef = new VersionReferenceJson(); versionRef.setVersion(extVersion.getVersion()); diff --git a/server/src/main/java/org/eclipse/openvsx/RegistryAPI.java b/server/src/main/java/org/eclipse/openvsx/RegistryAPI.java index b272a706b..b104ef0f7 100644 --- a/server/src/main/java/org/eclipse/openvsx/RegistryAPI.java +++ b/server/src/main/java/org/eclipse/openvsx/RegistryAPI.java @@ -505,6 +505,9 @@ public ResponseEntity getVersionReferences( String namespace, @PathVariable @Parameter(description = "Extension name", example = "svelte-vscode") String extension, + @RequestParam(required = false) + @Parameter(description = "If true, only preRelease versions are returned, if false only regular releases are returned, if omitted all versions are returned", schema = @Schema(type = "boolean", nullable = true)) + Boolean preReleases, @RequestParam(defaultValue = "18") @Parameter(description = "Maximal number of entries to return", schema = @Schema(type = "integer", minimum = "0", defaultValue = "18")) int size, @@ -512,7 +515,7 @@ public ResponseEntity getVersionReferences( @Parameter(description = "Number of entries to skip (usually a multiple of the page size)", schema = @Schema(type = "integer", minimum = "0", defaultValue = "0")) int offset ) { - return handleGetVersionReferences(namespace, extension, null, size, offset); + return handleGetVersionReferences(namespace, extension, null, BooleanTernary.ofBoolean(preReleases), size, offset); } @GetMapping( @@ -548,6 +551,9 @@ public ResponseEntity getVersionReferences( }) ) String targetPlatform, + @RequestParam(required = false) + @Parameter(description = "If true, only preRelease versions are returned, if false only regular releases are returned, if omitted all versions are returned", schema = @Schema(type = "boolean", nullable = true)) + Boolean preReleases, @RequestParam(defaultValue = "18") @Parameter(description = "Maximal number of entries to return", schema = @Schema(type = "integer", minimum = "0", defaultValue = "18")) int size, @@ -555,10 +561,10 @@ public ResponseEntity getVersionReferences( @Parameter(description = "Number of entries to skip (usually a multiple of the page size)", schema = @Schema(type = "integer", minimum = "0", defaultValue = "0")) int offset ) { - return handleGetVersionReferences(namespace, extension, targetPlatform, size, offset); + return handleGetVersionReferences(namespace, extension, targetPlatform, BooleanTernary.ofBoolean(preReleases), size, offset); } - private ResponseEntity handleGetVersionReferences(String namespace, String extension, String targetPlatform, int size, int offset) { + private ResponseEntity handleGetVersionReferences(String namespace, String extension, String targetPlatform, BooleanTernary preReleases, int size, int offset) { if (size < 0) { var json = VersionReferencesJson.error(negativeSizeMessage()); return new ResponseEntity<>(json, HttpStatus.BAD_REQUEST); @@ -571,7 +577,7 @@ private ResponseEntity handleGetVersionReferences(String try { return ResponseEntity.ok() .cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic()) - .body(registry.getVersionReferences(namespace, extension, targetPlatform, size, offset)); + .body(registry.getVersionReferences(namespace, extension, targetPlatform, preReleases, size, offset)); } catch (NotFoundException exc) { // Try the next registry } diff --git a/server/src/main/java/org/eclipse/openvsx/UpstreamRegistryService.java b/server/src/main/java/org/eclipse/openvsx/UpstreamRegistryService.java index 586572d45..90a56562e 100644 --- a/server/src/main/java/org/eclipse/openvsx/UpstreamRegistryService.java +++ b/server/src/main/java/org/eclipse/openvsx/UpstreamRegistryService.java @@ -12,6 +12,7 @@ import org.apache.commons.lang3.StringUtils; import org.eclipse.openvsx.json.*; import org.eclipse.openvsx.search.ISearchService; +import org.eclipse.openvsx.util.BooleanTernary; import org.eclipse.openvsx.util.NotFoundException; import org.eclipse.openvsx.util.TargetPlatform; import org.slf4j.Logger; @@ -41,6 +42,7 @@ public class UpstreamRegistryService implements IExtensionRegistry { private static final String VAR_NAMESPACE = "namespace"; private static final String VAR_EXTENSION = "extension"; private static final String VAR_TARGET = "targetPlatform"; + private static final String VAR_PRE_RELEASES = "preReleases"; private static final String VAR_OFFSET = "offset"; private static final String VAR_SIZE = "size"; private static final String VAR_ALL_VERSIONS = "includeAllVersions"; @@ -195,7 +197,7 @@ public VersionsJson getVersions(String namespace, String extension, String targe } @Override - public VersionReferencesJson getVersionReferences(String namespace, String extension, String targetPlatform, int size, int offset) { + public VersionReferencesJson getVersionReferences(String namespace, String extension, String targetPlatform, BooleanTernary preReleases, int size, int offset) { var urlTemplate = urlConfigService.getUpstreamUrl() + URL_EXTENSION_FRAGMENT; var uriVariables = new HashMap(); uriVariables.put(VAR_NAMESPACE, namespace); @@ -209,6 +211,11 @@ public VersionReferencesJson getVersionReferences(String namespace, String exten uriVariables.put(VAR_OFFSET, String.valueOf(offset)); uriVariables.put(VAR_SIZE, String.valueOf(size)); + if (preReleases != BooleanTernary.UNKNOWN) { + urlTemplate += "&preReleases={preReleases}"; + uriVariables.put(VAR_PRE_RELEASES, String.valueOf(preReleases)); + } + try { var json = restTemplate.getForObject(urlTemplate, VersionReferencesJson.class, uriVariables); return proxy != null ? proxy.rewriteUrls(json) : json; diff --git a/server/src/main/java/org/eclipse/openvsx/util/BooleanTernary.java b/server/src/main/java/org/eclipse/openvsx/util/BooleanTernary.java new file mode 100644 index 000000000..517ead19c --- /dev/null +++ b/server/src/main/java/org/eclipse/openvsx/util/BooleanTernary.java @@ -0,0 +1,35 @@ +/****************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * https://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.openvsx.util; + +public enum BooleanTernary { + TRUE, + FALSE, + UNKNOWN; + + @Override + public String toString() { + return name().toLowerCase(); + } + + public static BooleanTernary ofBoolean(Boolean value) { + if (value == null) { + return BooleanTernary.UNKNOWN; + } else if (value) { + return BooleanTernary.TRUE; + } else { + return BooleanTernary.FALSE; + } + } +} diff --git a/server/src/test/java/org/eclipse/openvsx/util/BooleanTernaryTest.java b/server/src/test/java/org/eclipse/openvsx/util/BooleanTernaryTest.java new file mode 100644 index 000000000..b954daad0 --- /dev/null +++ b/server/src/test/java/org/eclipse/openvsx/util/BooleanTernaryTest.java @@ -0,0 +1,36 @@ +/****************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation. + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * https://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.openvsx.util; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class BooleanTernaryTest { + + @Test + public void testOfBoolean() { + assertThat(BooleanTernary.ofBoolean(null)).isEqualTo(BooleanTernary.UNKNOWN); + assertThat(BooleanTernary.ofBoolean(true)).isEqualTo(BooleanTernary.TRUE); + assertThat(BooleanTernary.ofBoolean(false)).isEqualTo(BooleanTernary.FALSE); + } + + @Test + public void testToString() { + assertThat(BooleanTernary.TRUE.toString()).isEqualTo("true"); + assertThat(String.valueOf(BooleanTernary.TRUE)).isEqualTo("true"); + assertThat(BooleanTernary.FALSE.toString()).isEqualTo("false"); + assertThat(String.valueOf(BooleanTernary.FALSE)).isEqualTo("false"); + } +}