mirror of
https://gitee.com/dcren/initializr.git
synced 2026-02-25 21:22:58 +08:00
Add platform compatibility range support
This commit adds a new `platformCompatibilityRange` in the metadata that can be used to restrict the valid platform versions. If a project is requested or metadata needs to be resolved against a version that does not match the range, an exception is thrown. Closes gh-1048
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -186,6 +186,12 @@ public class InitializrMetadataTestBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public InitializrMetadataTestBuilder setPlatformCompatibilityRange(String platformCompatibilityRange) {
|
||||
this.builder.withCustomizer(
|
||||
(it) -> it.getConfiguration().getEnv().setPlatformCompatibilityRange(platformCompatibilityRange));
|
||||
return this;
|
||||
}
|
||||
|
||||
public InitializrMetadataTestBuilder setGradleEnv(String dependencyManagementPluginVersion) {
|
||||
this.builder.withCustomizer((it) -> it.getConfiguration().getEnv().getGradle()
|
||||
.setDependencyManagementPluginVersion(dependencyManagementPluginVersion));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -210,6 +210,16 @@ public class InitializrConfiguration {
|
||||
*/
|
||||
private boolean forceSsl;
|
||||
|
||||
/**
|
||||
* Compatibility range of supported platform versions. Requesting metadata or
|
||||
* project generation with a platform version that does not match this range is
|
||||
* not supported.
|
||||
*/
|
||||
private String platformCompatibilityRange;
|
||||
|
||||
@JsonIgnore
|
||||
private VersionRange compatibilityRange;
|
||||
|
||||
/**
|
||||
* The "BillOfMaterials" that are referenced in this instance, identified by an
|
||||
* arbitrary identifier that can be used in the dependencies definition.
|
||||
@@ -300,6 +310,14 @@ public class InitializrConfiguration {
|
||||
this.forceSsl = forceSsl;
|
||||
}
|
||||
|
||||
public String getPlatformCompatibilityRange() {
|
||||
return this.platformCompatibilityRange;
|
||||
}
|
||||
|
||||
public void setPlatformCompatibilityRange(String platformCompatibilityRange) {
|
||||
this.platformCompatibilityRange = platformCompatibilityRange;
|
||||
}
|
||||
|
||||
public String getArtifactRepository() {
|
||||
return this.artifactRepository;
|
||||
}
|
||||
@@ -335,6 +353,14 @@ public class InitializrConfiguration {
|
||||
this.maven.parent.validate();
|
||||
this.boms.forEach((k, v) -> v.validate());
|
||||
this.kotlin.validate();
|
||||
updateCompatibilityRange(VersionParser.DEFAULT);
|
||||
}
|
||||
|
||||
public void updateCompatibilityRange(VersionParser versionParser) {
|
||||
this.getBoms().values().forEach((it) -> it.updateCompatibilityRange(versionParser));
|
||||
this.getKotlin().updateCompatibilityRange(versionParser);
|
||||
this.compatibilityRange = (this.platformCompatibilityRange != null)
|
||||
? versionParser.parseRange(this.platformCompatibilityRange) : null;
|
||||
}
|
||||
|
||||
public void merge(Env other) {
|
||||
@@ -344,6 +370,8 @@ public class InitializrConfiguration {
|
||||
this.fallbackApplicationName = other.fallbackApplicationName;
|
||||
this.invalidApplicationNames = other.invalidApplicationNames;
|
||||
this.forceSsl = other.forceSsl;
|
||||
this.platformCompatibilityRange = other.platformCompatibilityRange;
|
||||
this.compatibilityRange = other.compatibilityRange;
|
||||
this.gradle.merge(other.gradle);
|
||||
this.kotlin.merge(other.kotlin);
|
||||
this.maven.merge(other.maven);
|
||||
@@ -351,6 +379,20 @@ public class InitializrConfiguration {
|
||||
other.repositories.forEach(this.repositories::putIfAbsent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether the specified {@linkplain Version platform version} is
|
||||
* supported.
|
||||
* @param platformVersion the platform version to check
|
||||
* @return {@code true} if this version is supported, {@code false} otherwise
|
||||
*/
|
||||
public boolean isCompatiblePlatformVersion(Version platformVersion) {
|
||||
return (this.compatibilityRange == null || this.compatibilityRange.match(platformVersion));
|
||||
}
|
||||
|
||||
public String determinePlatformCompatibilityRangeRequirement() {
|
||||
return this.compatibilityRange.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gradle details.
|
||||
*/
|
||||
@@ -421,18 +463,17 @@ public class InitializrConfiguration {
|
||||
}
|
||||
|
||||
public void validate() {
|
||||
VersionParser simpleParser = new VersionParser(Collections.emptyList());
|
||||
this.mappings.forEach((m) -> {
|
||||
if (m.compatibilityRange == null) {
|
||||
throw new InvalidInitializrMetadataException(
|
||||
"CompatibilityRange is mandatory, invalid version mapping for " + this);
|
||||
}
|
||||
m.range = simpleParser.parseRange(m.compatibilityRange);
|
||||
if (m.version == null) {
|
||||
throw new InvalidInitializrMetadataException(
|
||||
"Version is mandatory, invalid version mapping for " + this);
|
||||
}
|
||||
});
|
||||
updateCompatibilityRange(VersionParser.DEFAULT);
|
||||
}
|
||||
|
||||
public void updateCompatibilityRange(VersionParser versionParser) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -206,8 +206,7 @@ public class InitializrMetadata {
|
||||
.collect(Collectors.toList());
|
||||
VersionParser parser = new VersionParser(bootVersions);
|
||||
this.dependencies.updateCompatibilityRange(parser);
|
||||
this.configuration.getEnv().getBoms().values().forEach((it) -> it.updateCompatibilityRange(parser));
|
||||
this.configuration.getEnv().getKotlin().updateCompatibilityRange(parser);
|
||||
this.configuration.getEnv().updateCompatibilityRange(parser);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,6 +24,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import io.spring.initializr.generator.version.Version;
|
||||
import io.spring.initializr.metadata.DependencyMetadata;
|
||||
import io.spring.initializr.metadata.DependencyMetadataProvider;
|
||||
import io.spring.initializr.metadata.InitializrConfiguration.Env;
|
||||
import io.spring.initializr.metadata.InitializrMetadata;
|
||||
import io.spring.initializr.metadata.InitializrMetadataProvider;
|
||||
import io.spring.initializr.metadata.InvalidInitializrMetadataException;
|
||||
@@ -32,6 +33,7 @@ import io.spring.initializr.web.mapper.InitializrMetadataJsonMapper;
|
||||
import io.spring.initializr.web.mapper.InitializrMetadataV21JsonMapper;
|
||||
import io.spring.initializr.web.mapper.InitializrMetadataV2JsonMapper;
|
||||
import io.spring.initializr.web.mapper.InitializrMetadataVersion;
|
||||
import io.spring.initializr.web.project.InvalidProjectRequestException;
|
||||
|
||||
import org.springframework.http.CacheControl;
|
||||
import org.springframework.http.HttpStatus;
|
||||
@@ -97,6 +99,12 @@ public class ProjectMetadataController extends AbstractMetadataController {
|
||||
response.sendError(HttpStatus.BAD_REQUEST.value(), ex.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler
|
||||
public void invalidProjectRequest(HttpServletResponse response, InvalidProjectRequestException ex)
|
||||
throws IOException {
|
||||
response.sendError(HttpStatus.BAD_REQUEST.value(), ex.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link CacheControl} response headers to use for the specified
|
||||
* {@link InitializrMetadata metadata}. If no cache should be applied
|
||||
@@ -112,6 +120,11 @@ public class ProjectMetadataController extends AbstractMetadataController {
|
||||
InitializrMetadata metadata = this.metadataProvider.get();
|
||||
Version v = (bootVersion != null) ? Version.parse(bootVersion)
|
||||
: Version.parse(metadata.getBootVersions().getDefault().getId());
|
||||
Env env = metadata.getConfiguration().getEnv();
|
||||
if (!env.isCompatiblePlatformVersion(v)) {
|
||||
throw new InvalidProjectRequestException("Invalid Spring Boot version '" + bootVersion
|
||||
+ "', Spring Boot compatibility range is " + env.determinePlatformCompatibilityRangeRequirement());
|
||||
}
|
||||
DependencyMetadata dependencyMetadata = this.dependencyMetadataProvider.get(metadata, v);
|
||||
String content = new DependencyMetadataV21JsonMapper().write(dependencyMetadata);
|
||||
return ResponseEntity.ok().contentType(version.getMediaType()).eTag(createUniqueId(content))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,6 +27,7 @@ import io.spring.initializr.generator.project.ProjectDescription;
|
||||
import io.spring.initializr.generator.version.Version;
|
||||
import io.spring.initializr.metadata.DefaultMetadataElement;
|
||||
import io.spring.initializr.metadata.Dependency;
|
||||
import io.spring.initializr.metadata.InitializrConfiguration.Env;
|
||||
import io.spring.initializr.metadata.InitializrMetadata;
|
||||
import io.spring.initializr.metadata.Type;
|
||||
import io.spring.initializr.metadata.support.MetadataBuildItemMapper;
|
||||
@@ -42,8 +43,6 @@ import io.spring.initializr.metadata.support.MetadataBuildItemMapper;
|
||||
public class DefaultProjectRequestToDescriptionConverter
|
||||
implements ProjectRequestToDescriptionConverter<ProjectRequest> {
|
||||
|
||||
private static final Version VERSION_1_5_0 = Version.parse("1.5.0.RELEASE");
|
||||
|
||||
@Override
|
||||
public ProjectDescription convert(ProjectRequest request, InitializrMetadata metadata) {
|
||||
MutableProjectDescription description = new MutableProjectDescription();
|
||||
@@ -82,18 +81,19 @@ public class DefaultProjectRequestToDescriptionConverter
|
||||
}
|
||||
|
||||
private void validate(ProjectRequest request, InitializrMetadata metadata) {
|
||||
validateSpringBootVersion(request);
|
||||
validateSpringBootVersion(request, metadata);
|
||||
validateType(request.getType(), metadata);
|
||||
validateLanguage(request.getLanguage(), metadata);
|
||||
validatePackaging(request.getPackaging(), metadata);
|
||||
validateDependencies(request, metadata);
|
||||
}
|
||||
|
||||
private void validateSpringBootVersion(ProjectRequest request) {
|
||||
private void validateSpringBootVersion(ProjectRequest request, InitializrMetadata metadata) {
|
||||
Version bootVersion = Version.safeParse(request.getBootVersion());
|
||||
if (bootVersion != null && bootVersion.compareTo(VERSION_1_5_0) < 0) {
|
||||
throw new InvalidProjectRequestException(
|
||||
"Invalid Spring Boot version " + bootVersion + " must be 1.5.0 or higher");
|
||||
Env env = metadata.getConfiguration().getEnv();
|
||||
if (bootVersion != null && !env.isCompatiblePlatformVersion(bootVersion)) {
|
||||
throw new InvalidProjectRequestException("Invalid Spring Boot version '" + bootVersion
|
||||
+ "', Spring Boot compatibility range is " + env.determinePlatformCompatibilityRangeRequirement());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,9 @@ import io.spring.initializr.metadata.Dependency;
|
||||
import io.spring.initializr.web.AbstractInitializrControllerIntegrationTests;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -46,4 +48,29 @@ class ProjectGenerationControllerCustomEnvIntegrationTests extends AbstractIniti
|
||||
.hasDependency(Dependency.createSpringBootStarter("test", Dependency.SCOPE_TEST));
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateProjectWithUnsupportedPlatformVersion() {
|
||||
try {
|
||||
execute("/starter.zip?bootVersion=1.5.12.RELEASE", byte[].class, null, (String[]) null);
|
||||
}
|
||||
catch (HttpClientErrorException ex) {
|
||||
assertThat(ex.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
|
||||
assertThat(ex.getMessage()).contains("Invalid Spring Boot version",
|
||||
"Spring Boot compatibility range is >=2.0.0.RELEASE");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void getDependenciesMetadataWithUnsupportedPlatformVersion() {
|
||||
try {
|
||||
execute("/dependencies?bootVersion=1.5.12.RELEASE", String.class, "application/vnd.initializr.v2.1+json",
|
||||
"application/json");
|
||||
}
|
||||
catch (HttpClientErrorException ex) {
|
||||
assertThat(ex.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
|
||||
assertThat(ex.getMessage()).contains("Invalid Spring Boot version",
|
||||
"Spring Boot compatibility range is >=2.0.0.RELEASE");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -66,12 +66,23 @@ class DefaultProjectRequestToDescriptionConverterTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertWhenSpringBootVersionInvalidShouldThrowException() {
|
||||
void convertWhenPlatformCompatiblityRangeIsNotSetShouldNotThrowException() {
|
||||
this.metadata = InitializrMetadataTestBuilder.withDefaults().setPlatformCompatibilityRange(null).build();
|
||||
ProjectRequest request = createProjectRequest();
|
||||
request.setBootVersion("1.2.3.M4");
|
||||
request.setBootVersion("1.5.9.RELEASE");
|
||||
assertThat(this.converter.convert(request, this.metadata).getPlatformVersion())
|
||||
.isEqualTo(Version.parse("1.5.9.RELEASE"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void convertWhenSpringBootVersionInvalidShouldThrowException() {
|
||||
this.metadata = InitializrMetadataTestBuilder.withDefaults()
|
||||
.setPlatformCompatibilityRange("[2.0.0.RELEASE,2.3.0.M1)").build();
|
||||
ProjectRequest request = createProjectRequest();
|
||||
request.setBootVersion("1.5.9.RELEASE");
|
||||
assertThatExceptionOfType(InvalidProjectRequestException.class)
|
||||
.isThrownBy(() -> this.converter.convert(request, this.metadata))
|
||||
.withMessage("Invalid Spring Boot version 1.2.3.M4 must be 1.5.0 or higher");
|
||||
.isThrownBy(() -> this.converter.convert(request, this.metadata)).withMessage(
|
||||
"Invalid Spring Boot version '1.5.9.RELEASE', Spring Boot compatibility range is >=2.0.0.RELEASE and <2.3.0.M1");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -5,5 +5,6 @@ initializr:
|
||||
fallbackApplicationName: FooBarApplication
|
||||
invalidApplicationNames:
|
||||
- InvalidApplication
|
||||
platform-compatibility-range: "2.0.0.RELEASE"
|
||||
kotlin:
|
||||
default-version: 1.0.0-beta-2423
|
||||
@@ -33,6 +33,7 @@
|
||||
"artifactRepository": "https://repo.spring.io/release/",
|
||||
"fallbackApplicationName": "Application",
|
||||
"forceSsl": false,
|
||||
"platformCompatibilityRange": null,
|
||||
"gradle": {
|
||||
"dependencyManagementPluginVersion": "1.0.0.RELEASE"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user