Commit d8b75fb2 authored by Martin Lowe's avatar Martin Lowe 🇨🇦
Browse files

Add tests and openapi spec for application, update output of releases

Update to releases endpoint is to match current output. Also added
legacy functionality endpoint support to maintain current functionality.
Risk of cross-over is next to 0 with current naming scheme.
parent 9b881ecd
......@@ -81,3 +81,4 @@ docker.secret.properties
#Generated resources
/.apt_generated/
/.apt_generated_tests/
src/test/resources/schemas
......@@ -11,7 +11,7 @@
},
"private": true,
"scripts": {
"start": "npm run generate-json-schema && npx @redocly/openapi-cli preview-docs spec/openapi.yaml -p 8093",
"start": "npm run generate-json-schema && npx @redocly/openapi-cli preview-docs spec/openapi.yaml -p 8097",
"test": "npm run generate-json-schema && npx @redocly/openapi-cli lint spec/openapi.yaml",
"generate-json-schema": "npm run clean && node src/main/js/openapi2schema.js -s spec/openapi.yaml -t src/test/resources",
"clean": "rm -rf src/test/resources/schemas/"
......
......@@ -69,14 +69,6 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc-client-filter</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client</artifactId>
......
openapi: '3.1.0'
info:
version: 1.0.0
title: Eclipse Foundation Downloads API
license:
name: Eclipse Public License - 2.0
url: https://www.eclipse.org/legal/epl-2.0/
servers:
- url: https://api.eclipse.org/download
description: Production endpoint for the download information
tags:
- name: Files
description: Definitions in relation to retrieval of mailing lists
- name: Releases
description: Definitions in relation to retrieval of mailing lists
paths:
/file/{file_id}:
get:
tags:
- Files
summary: File by ID
description: Returns a file indexes metadata by its file ID
responses:
200:
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/File'
500:
description: Error while retrieving data
/release/{releaseType}:
parameters:
- name: releaseType
in: path
description: The type of release to retrieve
required: true
schema:
type: string
enum:
- epp
- eclipse_packages
- name: release_name
in: query
description: The name of the release to retrieve
required: true
schema:
type: string
- name: release_version
in: query
description: The version of the release to retrieve
schema:
type: string
get:
tags:
- Releases
summary: Releases by release type
description: Returns a list of releases, or a single release, applicable to the query parameters
responses:
200:
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/Release'
500:
description: Error while retrieving data
/release/{releaseName}:
parameters:
- name: releaseName
in: path
description: The name of the release to retrieve
required: true
schema:
type: string
get:
tags:
- Releases
summary: Release Versions
description: Returns a list of versions available for the given release
responses:
200:
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/Releases'
500:
description: Error while retrieving data
/release/{releaseName}/{releaseVersion}:
parameters:
- name: releaseName
in: path
description: The name of the release to retrieve
required: true
schema:
type: string
- name: releaseVersion
in: path
description: The version of the release to retrieve
required: true
schema:
type: string
get:
tags:
- Releases
summary: Release Version
description: Returns a given version for the named release
responses:
200:
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/Release'
500:
description: Error while retrieving data
components:
schemas:
NullableString:
description: A nullable String type value
oneOf:
- type: 'null'
- type: string
DateTime:
type: string
format: datetime
description: |
Date string in the RFC 3339 format. Example, `1990-12-31T15:59:60-08:00`.
More on this standard can be read at https://tools.ietf.org/html/rfc3339.
Files:
type: array
items:
$ref: '#/components/schemas/File'
File:
type: object
properties:
file_id:
type: integer
description: placeholder
file_name:
type: string
description: placeholder
download_count:
type: integer
description: placeholder
size_disk_bytes:
type: integer
description: placeholder
timestamp_disk:
type: integer
description: placeholder
md5sum:
$ref: '#/components/schemas/NullableString'
description: placeholder
sha1sum:
$ref: '#/components/schemas/NullableString'
description: placeholder
Releases:
type: array
items:
$ref: '#/components/schemas/Release'
Release:
type: object
properties:
release_name:
type: string
description: The name of the release for the packages
release_version:
type: string
description: The version of the release for the packages
packages:
type: object
properties:
java-package:
$ref: '#/components/schemas/ReleasePackage'
jee-package:
$ref: '#/components/schemas/ReleasePackage'
cpp-package:
$ref: '#/components/schemas/ReleasePackage'
committers-package:
$ref: '#/components/schemas/ReleasePackage'
php-package:
$ref: '#/components/schemas/ReleasePackage'
dsl-package:
$ref: '#/components/schemas/ReleasePackage'
embedcpp-package:
$ref: '#/components/schemas/ReleasePackage'
modeling-package:
$ref: '#/components/schemas/ReleasePackage'
rcp-package:
$ref: '#/components/schemas/ReleasePackage'
parallel-package:
$ref: '#/components/schemas/ReleasePackage'
scout-package:
$ref: '#/components/schemas/ReleasePackage'
ReleasePackage:
type: object
properties:
name:
type: string
description: The name of the release package
package_bugzilla_id:
type: string
description: Placeholder
download_count:
type: string
description: Number of times this package has been downloaded
website_url:
type: string
description: The public URL for the package that includes more information about the release.
incubating:
type: boolean
description: placeholder
class:
type: string
description: placeholder
body:
type: string
description: Description of the release package
features:
type: array
items:
type: string
files:
type: object
properties:
mac:
$ref: '#/components/schemas/ReleaseFiles'
windows:
$ref: '#/components/schemas/ReleaseFiles'
linux:
$ref: '#/components/schemas/ReleaseFiles'
ReleaseFiles:
type: object
properties:
32:
oneOf:
- $ref: '#/components/schemas/ReleaseFile'
- type: 'null'
64:
oneOf:
- $ref: '#/components/schemas/ReleaseFile'
- type: 'null'
ReleaseFile:
type: object
properties:
url:
type: string
description: The publicly available URL for the package
size:
type: string
description: the size of the file in bytes
file_id:
$ref: '#/components/schemas/NullableString'
description: The internal ID of the file
file_url:
type: string
description: the public facing URL for the file (no mirror)
download_count:
type: string
description: The number of times this file has been downloaded
checksum:
type: object
properties:
sha1:
$ref: '#/components/schemas/NullableString'
description: the sha1 checksum for the release file
md5:
$ref: '#/components/schemas/NullableString'
description: the md5 checksum for the release file
sha512:
$ref: '#/components/schemas/NullableString'
description: the sha512 checksum for the release file
......@@ -6,6 +6,7 @@ import javax.ws.rs.PathParam;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import org.eclipsefoundation.downloads.models.ReleaseTrackerPackages;
import org.eclipsefoundation.downloads.models.TrackedReleases;
import org.jboss.resteasy.annotations.GZIP;
@GZIP
......@@ -13,6 +14,10 @@ import org.jboss.resteasy.annotations.GZIP;
public interface DrupalAPI {
@GET
@Path("downloads/packages/admin/release_tracker/json/{releasePackageName}/all")
ReleaseTrackerPackages get(@PathParam("releasePackageName") String releasePackageName);
@Path("downloads/packages/admin/release_tracker/json/")
TrackedReleases getTrackedReleases();
@GET
@Path("downloads/packages/admin/release_tracker/json/{releaseName}%20{version}/all")
ReleaseTrackerPackages get(@PathParam("releaseName") String releaseName, @PathParam("version") String version);
}
......@@ -8,6 +8,7 @@ import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import javax.ws.rs.core.MultivaluedMap;
import org.apache.commons.lang3.StringUtils;
import org.eclipsefoundation.core.namespace.DefaultUrlParameterNames;
import org.eclipsefoundation.downloads.namespaces.DownloadsUrlParameterNames;
import org.eclipsefoundation.persistence.dto.BareNode;
......@@ -148,9 +149,9 @@ public class DownloadFileIndex extends BareNode {
if (isRoot) {
// ID check
String id = params.getFirst(DefaultUrlParameterNames.ID.getName());
if (id != null) {
if (StringUtils.isNumeric(id)) {
stmt.addClause(new ParameterizedSQLStatement.Clause(TABLE.getAlias() + ".fileId = ?",
new Object[] { id }));
new Object[] { Integer.valueOf(id) }));
}
// file name check
String fileName = params.getFirst(DownloadsUrlParameterNames.FILE_NAME.getName());
......
......@@ -114,7 +114,7 @@ public abstract class ReleaseTrackerPackages {
public abstract List<String> getFeatures();
public abstract Object getFiles();
public abstract OSReleases getFiles();
public static Builder builder() {
return new AutoValue_ReleaseTrackerPackages_ReleaseTrackerPackage.Builder();
......@@ -140,7 +140,7 @@ public abstract class ReleaseTrackerPackages {
public abstract Builder setFeatures(List<String> features);
public abstract Builder setFiles(Object files);
public abstract Builder setFiles(OSReleases files);
public abstract ReleaseTrackerPackage build();
}
......@@ -206,6 +206,7 @@ public abstract class ReleaseTrackerPackages {
public abstract String getSize();
@Nullable
public abstract String getFileId();
public abstract String getFileUrl();
......@@ -225,7 +226,7 @@ public abstract class ReleaseTrackerPackages {
public abstract Builder setSize(String size);
public abstract Builder setFileId(String fileId);
public abstract Builder setFileId(@Nullable String fileId);
public abstract Builder setFileUrl(String fileUrl);
......@@ -240,10 +241,13 @@ public abstract class ReleaseTrackerPackages {
@AutoValue
@JsonDeserialize(builder = AutoValue_ReleaseTrackerPackages_Checksums.Builder.class)
public abstract static class Checksums {
@Nullable
public abstract String getMd5();
@Nullable
public abstract String getSha1();
@Nullable
public abstract String getSha512();
public static Builder builder() {
......@@ -253,11 +257,11 @@ public abstract class ReleaseTrackerPackages {
@AutoValue.Builder
@JsonPOJOBuilder(withPrefix = "set")
public abstract static class Builder {
public abstract Builder setMd5(String md5);
public abstract Builder setMd5(@Nullable String md5);
public abstract Builder setSha1(String sha1);
public abstract Builder setSha1(@Nullable String sha1);
public abstract Builder setSha512(String sha512);
public abstract Builder setSha512(@Nullable String sha512);
public abstract Checksums build();
}
......
package org.eclipsefoundation.downloads.models;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.google.auto.value.AutoValue;
@AutoValue
@JsonDeserialize(builder = AutoValue_ReleaseVersionPackages.Builder.class)
public abstract class ReleaseVersionPackages {
public abstract String getReleaseName();
public abstract String getReleaseVersion();
public abstract ReleaseTrackerPackages getPackages();
public static Builder builder() {
return new AutoValue_ReleaseVersionPackages.Builder();
}
@AutoValue.Builder
@JsonPOJOBuilder(withPrefix = "set")
public abstract static class Builder {
public abstract Builder setReleaseName(String releaseName);
public abstract Builder setReleaseVersion(String releaseVersion);
public abstract Builder setPackages(ReleaseTrackerPackages packages);
public abstract ReleaseVersionPackages build();
}
}
......@@ -31,7 +31,7 @@ public abstract class TrackedReleases {
public abstract static class Release {
public abstract String getName();
public abstract List<ReleasePackage> getReleasePackages();
public abstract List<ReleaseVersion> getVersions();
public static Builder builder() {
return new AutoValue_TrackedReleases_Release.Builder();
......@@ -42,15 +42,15 @@ public abstract class TrackedReleases {
public abstract static class Builder {
public abstract Builder setName(String name);
public abstract Builder setReleasePackages(List<ReleasePackage> releases);
public abstract Builder setVersions(List<ReleaseVersion> version);
public abstract Release build();
}
}
@AutoValue
@JsonDeserialize(builder = AutoValue_TrackedReleases_ReleasePackage.Builder.class)
public abstract static class ReleasePackage {
@JsonDeserialize(builder = AutoValue_TrackedReleases_ReleaseVersion.Builder.class)
public abstract static class ReleaseVersion {
public abstract String getName();
public abstract String getType();
......@@ -61,7 +61,7 @@ public abstract class TrackedReleases {
public abstract Boolean getIsCurrent();
public static Builder builder() {
return new AutoValue_TrackedReleases_ReleasePackage.Builder();
return new AutoValue_TrackedReleases_ReleaseVersion.Builder();
}
@AutoValue.Builder
......@@ -75,7 +75,7 @@ public abstract class TrackedReleases {
public abstract Builder setIsCurrent(@Nullable Boolean isCurrent);
public abstract ReleasePackage build();
public abstract ReleaseVersion build();
}
}
}
......@@ -11,14 +11,19 @@ import org.eclipsefoundation.core.namespace.UrlParameterNamespace;
@Singleton
public final class DownloadsUrlParameterNames implements UrlParameterNamespace {
public static final String RELEASE_NAME_VALUE = "release_name";
public static final String RELEASE_VERSION_VALUE = "release_version";
public static final UrlParameter MIRROR_ID = new UrlParameter("mirror_id");
public static final UrlParameter CCODE = new UrlParameter("ccode");
public static final UrlParameter REMOTE_ADDR = new UrlParameter("remote_addr");
public static final UrlParameter REMOTE_HOST = new UrlParameter("remote_host");
public static final UrlParameter FILE_NAME = new UrlParameter("file_name");
public static final UrlParameter RELEASE_NAME = new UrlParameter(RELEASE_NAME_VALUE);
public static final UrlParameter RELEASE_VERSION = new UrlParameter(RELEASE_VERSION_VALUE);
private static final List<UrlParameter> params = Collections
.unmodifiableList(Arrays.asList(MIRROR_ID, CCODE, REMOTE_ADDR, REMOTE_HOST, FILE_NAME));
private static final List<UrlParameter> params = Collections.unmodifiableList(
Arrays.asList(MIRROR_ID, CCODE, REMOTE_ADDR, REMOTE_HOST, FILE_NAME, RELEASE_NAME, RELEASE_VERSION));
@Override
public List<UrlParameter> getParameters() {
......
package org.eclipsefoundation.downloads.resources;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.eclipsefoundation.core.model.Error;
import org.eclipsefoundation.core.model.RequestWrapper;
import org.eclipsefoundation.core.namespace.DefaultUrlParameterNames;
import org.eclipsefoundation.core.service.CachingService;
import org.eclipsefoundation.downloads.api.DrupalAPI;
import org.eclipsefoundation.downloads.dto.DownloadFileIndex;
import org.eclipsefoundation.downloads.models.ReleaseTrackerPackages;
import org.eclipsefoundation.downloads.models.ReleaseVersionPackages;
import org.eclipsefoundation.downloads.models.TrackedReleases.Release;
import org.eclipsefoundation.downloads.models.TrackedReleases.ReleasePackage;
import org.eclipsefoundation.downloads.services.RawHttpClientService;
import org.eclipsefoundation.downloads.namespaces.DownloadsUrlParameterNames;
import org.eclipsefoundation.downloads.services.ReleaseTrackerService;
import org.eclipsefoundation.persistence.dao.impl.DefaultHibernateDao;
import org.eclipsefoundation.persistence.model.RDBMSQuery;
......@@ -46,7 +52,7 @@ public class DownloadsResource {
@Inject
@RestClient
DrupalAPI api;
@Inject
ReleaseTrackerService releaseTrackerService;
......@@ -59,31 +65,80 @@ public class DownloadsResource {
@GET
@Path("file/{id}")
public Response byID(@PathParam("id") String id) {
// filter by ID for the file index
MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
params.add(DefaultUrlParameterNames.ID.getName(), id);
return Response.ok(dao.get(new RDBMSQuery<>(wrap, filters.get(DownloadFileIndex.class), params))).build();
// get the index, and make sure we have a result
List<DownloadFileIndex> dfis = dao.get(new RDBMSQuery<>(wrap, filters.get(DownloadFileIndex.class), params));
if (dfis.isEmpty()) {
String message = String.format("No DownloadFileIndex found with id '%s'", id);
LOGGER.debug(message);
return new Error(404, message).asResponse();
}
return Response.ok(dfis.get(0)).build();
}
@GET
@Path("release/{type:(epp|eclipse_packages)}")
public Response packageRelease(@QueryParam(DownloadsUrlParameterNames.RELEASE_NAME_VALUE) String releaseName,
@QueryParam(DownloadsUrlParameterNames.RELEASE_VERSION_VALUE) String releaseVersion) {
if (StringUtils.isNotBlank(releaseName) && StringUtils.isNotBlank(releaseVersion)) {
return releaseVersion(releaseName, releaseVersion);
} else if (StringUtils.isNotBlank(releaseName)) {
return release(releaseName);
}
return new Error(400, "At least the release_name query parameter is required to use this endpoint")
.asResponse();
}
@GET
@Path("release/{releaseName}")
public Response release(@PathParam("releaseName") String releaseName) {
Optional<Release> r = releaseTrackerService.getReleaseByName(releaseName);
if (r.isEmpty()) {
String message = String.format("No release named '%s' found in store, cannot continue", releaseName);
LOGGER.debug(message);
<