mirror of
https://gitee.com/dcren/initializr.git
synced 2025-05-05 21:28:03 +08:00
Add version range support for dependencies
Previously, it was not possible to define the Spring Boot version that a dependency requires. As a result, many new starters implemented as part of Spring Boot 1.2 are not available. Each dependency can now define a `versionRange` attribute that defines the Spring Boot version range that it supports. The range is defined either as a single version, in which case it defines that version and any later versions or using brackets. A square bracket (`[` or `]`) denotes an inclusive range while a round bracket (`(` or `)`) denotes an exclusive range. Bumped the current-metadata format to 2.1 to include this additional `versionRange` attribute, that is application/vnd.initializr.v2.1+json Existing clients requesting v2 will not get any dependency that defines a `versionRange` attribute. Closes gh-62
This commit is contained in:
parent
8c0dc68a51
commit
da2ced86f3
@ -7,6 +7,7 @@ order.
|
||||
|
||||
=== Release 1.0.0 (In progress)
|
||||
|
||||
* https://github.com/spring-io/initializr/issues/62[#62]: add version range support.
|
||||
* https://github.com/spring-io/initializr/issues/75[#75]: migrate smoke tests to Geb.
|
||||
* https://github.com/spring-io/initializr/issues/74[#74]: remove support for meta-data V1.
|
||||
* https://github.com/spring-io/initializr/issues/71[#71]: update project layout for Groovy-based projects.
|
||||
|
@ -4,7 +4,7 @@ info:
|
||||
version: 0.3.1
|
||||
# remember to update static/install.sh as well:
|
||||
spring-boot:
|
||||
version: 1.2.0.RELEASE
|
||||
version: 1.2.1.RELEASE
|
||||
|
||||
initializr:
|
||||
dependencies:
|
||||
@ -16,6 +16,14 @@ initializr:
|
||||
- name: AOP
|
||||
id: aop
|
||||
description: Support for aspect-oriented programming including spring-aop and AspectJ
|
||||
- name: Atomikos (JTA)
|
||||
id: jta-atomikos
|
||||
description: Support for JTA distributed transactions via Atomikos
|
||||
versionRange: 1.2.0.M1
|
||||
- name: Bitronix (JTA)
|
||||
id: jta-bitronix
|
||||
description: Support for JTA distributed transactions via Bitronix
|
||||
versionRange: 1.2.0.M1
|
||||
- name: Data
|
||||
content:
|
||||
- name: JDBC
|
||||
@ -55,6 +63,10 @@ initializr:
|
||||
- name: AMQP
|
||||
id: amqp
|
||||
description: Support for the Advanced Message Queuing Protocol via spring-rabbit
|
||||
- name: Mail
|
||||
id: mail
|
||||
description: Support for javax.mail
|
||||
versionRange: 1.2.0.RC1
|
||||
- name: Web
|
||||
content:
|
||||
- name: Web
|
||||
@ -68,9 +80,17 @@ initializr:
|
||||
- name: WS
|
||||
id: ws
|
||||
description: Support for Spring Web Services
|
||||
- name: Jersey (JAX-RS)
|
||||
id: jersey
|
||||
description: Support for the Jersey RESTful Web Services framework
|
||||
versionRange: 1.2.0.RELEASE
|
||||
- name: Rest Repositories
|
||||
id: data-rest
|
||||
description: Support for exposing Spring Data repositories over REST via spring-data-rest-webmvc
|
||||
- name: HATEOAS
|
||||
id: hateoas
|
||||
description: Support for HATEOAS-based RESTful services
|
||||
versionRange: 1.2.2.BUILD-SNAPSHOT
|
||||
- name: Mobile
|
||||
id: mobile
|
||||
description: Support for spring-mobile
|
||||
@ -96,6 +116,12 @@ initializr:
|
||||
description: Support for the Thymeleaf templating engine, including integration with Spring
|
||||
facets:
|
||||
- web
|
||||
- name: Mustache
|
||||
id: mustache
|
||||
description: Support for the Mustache templating engine
|
||||
versionRange: 1.2.2.BUILD-SNAPSHOT
|
||||
facets:
|
||||
- web
|
||||
- name: Social
|
||||
content:
|
||||
- name: Facebook
|
||||
@ -112,6 +138,10 @@ initializr:
|
||||
- name: Actuator
|
||||
id: actuator
|
||||
description: Production ready features to help you monitor and manage your application
|
||||
- name: Cloud Connectors
|
||||
id: cloud-connectors
|
||||
description: Simplifies connecting to services in cloud platforms
|
||||
versionRange: 1.2.0.RELEASE
|
||||
- name: Remote Shell
|
||||
id: remote-shell
|
||||
description: Support for CRaSH
|
||||
|
@ -20,6 +20,11 @@ import javax.annotation.PostConstruct
|
||||
|
||||
import groovy.transform.ToString
|
||||
import groovy.util.logging.Slf4j
|
||||
import io.spring.initializr.mapper.InitializrMetadataJsonMapper
|
||||
import io.spring.initializr.mapper.InitializrMetadataV21JsonMapper
|
||||
import io.spring.initializr.mapper.InitializrMetadataV2JsonMapper
|
||||
import io.spring.initializr.support.InvalidVersionException
|
||||
import io.spring.initializr.support.VersionRange
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||
|
||||
@ -61,8 +66,6 @@ class InitializrMetadata {
|
||||
|
||||
private final Map<String, Dependency> indexedDependencies = [:]
|
||||
|
||||
private final transient InitializrMetadataJsonMapper jsonMapper = new InitializrMetadataJsonMapper()
|
||||
|
||||
/**
|
||||
* Return the {@link Dependency} with the specified id or {@code null} if
|
||||
* no such dependency exists.
|
||||
@ -127,11 +130,11 @@ class InitializrMetadata {
|
||||
|
||||
/**
|
||||
* Generate a JSON representation of the current metadata
|
||||
*
|
||||
* @param version the meta-data version
|
||||
* @param appUrl the application url
|
||||
*/
|
||||
String generateJson(String appUrl) {
|
||||
jsonMapper.write(this, appUrl)
|
||||
String generateJson(InitializrMetadataVersion version, String appUrl) {
|
||||
getJsonMapper(version).write(this, appUrl)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -193,6 +196,14 @@ class InitializrMetadata {
|
||||
"Invalid dependency, id should have the form groupId:artifactId[:version] but got $id")
|
||||
}
|
||||
}
|
||||
if (dependency.versionRange) {
|
||||
try {
|
||||
VersionRange.parse(dependency.versionRange)
|
||||
} catch (InvalidVersionException ex) {
|
||||
throw new InvalidInitializrMetadataException("Invalid version range '$dependency.versionRange' for " +
|
||||
"dependency with id '$dependency.id'")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static def getDefault(List elements) {
|
||||
@ -205,6 +216,13 @@ class InitializrMetadata {
|
||||
return (elements.isEmpty() ? null : elements.get(0).id)
|
||||
}
|
||||
|
||||
private static InitializrMetadataJsonMapper getJsonMapper(InitializrMetadataVersion version) {
|
||||
switch(version) {
|
||||
case InitializrMetadataVersion.V2: return new InitializrMetadataV2JsonMapper();
|
||||
default: return new InitializrMetadataV21JsonMapper();
|
||||
}
|
||||
}
|
||||
|
||||
static class DependencyGroup {
|
||||
|
||||
String name
|
||||
@ -228,6 +246,8 @@ class InitializrMetadata {
|
||||
|
||||
String description
|
||||
|
||||
String versionRange
|
||||
|
||||
/**
|
||||
* Specify if the dependency has its coordinates set, i.e. {@code groupId}
|
||||
* and {@code artifactId}.
|
||||
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2012-2015 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.spring.initializr
|
||||
|
||||
import org.springframework.http.MediaType
|
||||
|
||||
/**
|
||||
* Define the supported meta-data version.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.0
|
||||
*/
|
||||
enum InitializrMetadataVersion {
|
||||
|
||||
/**
|
||||
* HAL-compliant metadata.
|
||||
*/
|
||||
V2('application/vnd.initializr.v2+json'),
|
||||
|
||||
/**
|
||||
* Add 'versionRange' attribute to any dependency to specify which
|
||||
* Spring Boot versions are compatible with it.
|
||||
*/
|
||||
V2_1('application/vnd.initializr.v2.1+json')
|
||||
|
||||
private final MediaType mediaType;
|
||||
|
||||
InitializrMetadataVersion(String mediaType) {
|
||||
this.mediaType = MediaType.parseMediaType(mediaType)
|
||||
}
|
||||
|
||||
MediaType getMediaType() {
|
||||
return mediaType
|
||||
}
|
||||
|
||||
}
|
@ -17,6 +17,8 @@
|
||||
package io.spring.initializr
|
||||
|
||||
import groovy.util.logging.Slf4j
|
||||
import io.spring.initializr.support.Version
|
||||
import io.spring.initializr.support.VersionRange
|
||||
|
||||
/**
|
||||
* A request to generate a project.
|
||||
@ -79,12 +81,21 @@ class ProjectRequest {
|
||||
}
|
||||
dependency
|
||||
}
|
||||
String actualBootVersion = bootVersion ?: metadata.defaults.bootVersion
|
||||
Version requestedVersion = Version.parse(actualBootVersion)
|
||||
resolvedDependencies.each {
|
||||
it.facets.each {
|
||||
if (!facets.contains(it)) {
|
||||
facets.add(it)
|
||||
}
|
||||
}
|
||||
if (it.versionRange) {
|
||||
def range = VersionRange.parse(it.versionRange)
|
||||
if (!range.match(requestedVersion)) {
|
||||
throw new InvalidProjectRequestException("Dependency '$it.id' is not compatible " +
|
||||
"with Spring Boot $bootVersion")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.type) {
|
||||
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2012-2015 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.spring.initializr.mapper
|
||||
|
||||
import io.spring.initializr.InitializrMetadata
|
||||
|
||||
/**
|
||||
* Generate a JSON representation of the metadata.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.0
|
||||
*/
|
||||
interface InitializrMetadataJsonMapper {
|
||||
|
||||
/**
|
||||
* Write a json representation of the specified meta-data.
|
||||
*/
|
||||
String write(InitializrMetadata metadata, String appUrl);
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2012-2015 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.spring.initializr.mapper
|
||||
|
||||
/**
|
||||
* A {@link InitializrMetadataJsonMapper} handling the meta-data format for v2.1
|
||||
* <p>
|
||||
* Version 2.1 brings the 'versionRange' attribute for a dependency to restrict
|
||||
* the Spring Boot versions that can be used against it.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.0
|
||||
*/
|
||||
class InitializrMetadataV21JsonMapper extends InitializrMetadataV2JsonMapper {
|
||||
|
||||
@Override
|
||||
protected mapDependency(dependency) {
|
||||
def content = mapValue(dependency)
|
||||
if (dependency.versionRange) {
|
||||
content['versionRange'] = dependency.versionRange
|
||||
}
|
||||
content
|
||||
}
|
||||
}
|
@ -14,25 +14,27 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.spring.initializr
|
||||
package io.spring.initializr.mapper
|
||||
|
||||
import groovy.json.JsonBuilder
|
||||
import io.spring.initializr.InitializrMetadata
|
||||
|
||||
import org.springframework.hateoas.TemplateVariable
|
||||
import org.springframework.hateoas.TemplateVariables
|
||||
import org.springframework.hateoas.UriTemplate
|
||||
import org.springframework.util.StringUtils
|
||||
|
||||
/**
|
||||
* Generate a JSON representation of the metadata.
|
||||
* A {@link InitializrMetadataJsonMapper} handling the meta-data format for v2.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.0
|
||||
*/
|
||||
class InitializrMetadataJsonMapper {
|
||||
class InitializrMetadataV2JsonMapper implements InitializrMetadataJsonMapper {
|
||||
|
||||
private final TemplateVariables templateVariables
|
||||
|
||||
InitializrMetadataJsonMapper() {
|
||||
InitializrMetadataV2JsonMapper() {
|
||||
this.templateVariables = new TemplateVariables(
|
||||
new TemplateVariable('dependencies', TemplateVariable.VariableType.REQUEST_PARAM),
|
||||
new TemplateVariable('packaging', TemplateVariable.VariableType.REQUEST_PARAM),
|
||||
@ -48,6 +50,7 @@ class InitializrMetadataJsonMapper {
|
||||
)
|
||||
}
|
||||
|
||||
@Override
|
||||
String write(InitializrMetadata metadata, String appUrl) {
|
||||
JsonBuilder json = new JsonBuilder()
|
||||
json {
|
||||
@ -68,7 +71,7 @@ class InitializrMetadataJsonMapper {
|
||||
json.toString()
|
||||
}
|
||||
|
||||
private links(parent, types, appUrl) {
|
||||
protected links(parent, types, appUrl) {
|
||||
def content = [:]
|
||||
types.each {
|
||||
content[it.id] = link(appUrl, it)
|
||||
@ -76,7 +79,7 @@ class InitializrMetadataJsonMapper {
|
||||
parent._links content
|
||||
}
|
||||
|
||||
private link(appUrl, type) {
|
||||
protected link(appUrl, type) {
|
||||
def result = [:]
|
||||
result.href = generateTemplatedUri(appUrl, type)
|
||||
result.templated = true
|
||||
@ -91,41 +94,40 @@ class InitializrMetadataJsonMapper {
|
||||
}
|
||||
|
||||
|
||||
private static dependencies(parent, groups) {
|
||||
protected dependencies(parent, groups) {
|
||||
parent.dependencies {
|
||||
type 'hierarchical-multi-select'
|
||||
values groups.collect {
|
||||
processDependencyGroup(it)
|
||||
mapDependencyGroup(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static type(parent, defaultValue, dependencies) {
|
||||
protected type(parent, defaultValue, dependencies) {
|
||||
parent.type {
|
||||
type 'action'
|
||||
if (defaultValue) {
|
||||
'default' defaultValue
|
||||
}
|
||||
values dependencies.collect {
|
||||
processType(it)
|
||||
mapType(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static singleSelect(parent, name, defaultValue, itemValues) {
|
||||
protected singleSelect(parent, name, defaultValue, itemValues) {
|
||||
parent."$name" {
|
||||
type 'single-select'
|
||||
if (defaultValue) {
|
||||
'default' defaultValue
|
||||
}
|
||||
values itemValues.collect {
|
||||
processValue(it)
|
||||
mapValue(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static text(parent, name, value) {
|
||||
protected text(parent, name, value) {
|
||||
parent."$name" {
|
||||
type 'text'
|
||||
if (value) {
|
||||
@ -134,8 +136,7 @@ class InitializrMetadataJsonMapper {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static processDependencyGroup(group) {
|
||||
protected mapDependencyGroup(group) {
|
||||
def result = [:]
|
||||
result.name = group.name
|
||||
if (group.hasProperty('description') && group.description) {
|
||||
@ -143,20 +144,29 @@ class InitializrMetadataJsonMapper {
|
||||
}
|
||||
def items = []
|
||||
group.content.collect {
|
||||
items << processValue(it)
|
||||
def dependency = mapDependency(it)
|
||||
if (dependency) {
|
||||
items << dependency
|
||||
}
|
||||
}
|
||||
result.values = items
|
||||
result
|
||||
}
|
||||
|
||||
private static processType(type) {
|
||||
def result = processValue(type)
|
||||
protected mapDependency(dependency) {
|
||||
if (!dependency.versionRange) { // only map the dependency if no versionRange is set
|
||||
mapValue(dependency)
|
||||
}
|
||||
}
|
||||
|
||||
protected mapType(type) {
|
||||
def result = mapValue(type)
|
||||
result.action = type.action
|
||||
result.tags = type.tags
|
||||
result
|
||||
}
|
||||
|
||||
private static processValue(value) {
|
||||
protected mapValue(value) {
|
||||
def result = [:]
|
||||
result.id = value.id
|
||||
result.name = value.name
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2012-2015 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.spring.initializr.support
|
||||
|
||||
import groovy.transform.InheritConstructors
|
||||
|
||||
/**
|
||||
* Thrown if a input represents an invalid version.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@InheritConstructors
|
||||
class InvalidVersionException extends RuntimeException {
|
||||
|
||||
}
|
@ -19,6 +19,8 @@ package io.spring.initializr.support
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.ToString
|
||||
|
||||
import org.springframework.util.Assert
|
||||
|
||||
/**
|
||||
* Define the version number of a module. A typical version is represented
|
||||
* as {@code MAJOR.MINOR.PATCH.QUALIFER} where the qualifier can have an
|
||||
@ -49,16 +51,18 @@ class Version implements Comparable<Version> {
|
||||
|
||||
/**
|
||||
* Parse the string representation of a {@link Version}. Throws an
|
||||
* {@link IllegalArgumentException} if the version could not be parsed.
|
||||
* {@link InvalidVersionException} if the version could not be parsed.
|
||||
* @param text the version text
|
||||
* @return a Version instance for the specified version text
|
||||
* @throws IllegalArgumentException if the version text could not be parsed
|
||||
* @throws InvalidVersionException if the version text could not be parsed
|
||||
* @see #safeParse(java.lang.String)
|
||||
*/
|
||||
static Version parse(String text) {
|
||||
def matcher = (text =~ VERSION_REGEX)
|
||||
Assert.notNull(text, 'Text must not be null')
|
||||
def matcher = (text.trim() =~ VERSION_REGEX)
|
||||
if (!matcher.matches()) {
|
||||
throw new IllegalArgumentException("Could not determine version based on $text")
|
||||
throw new InvalidVersionException("Could not determine version based on '$text': version format " +
|
||||
"is Minor.Major.Patch.Qualifier (i.e. 1.0.5.RELEASE")
|
||||
}
|
||||
Version version = new Version()
|
||||
version.major = Integer.valueOf(matcher[0][1])
|
||||
@ -87,7 +91,7 @@ class Version implements Comparable<Version> {
|
||||
static safeParse(String text) {
|
||||
try {
|
||||
return parse(text)
|
||||
} catch (IllegalArgumentException e) {
|
||||
} catch (InvalidVersionException e) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2012-2015 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.spring.initializr.support
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.ToString
|
||||
|
||||
import org.springframework.util.Assert
|
||||
|
||||
/**
|
||||
* Define a {@link Version} range. A square bracket "[" or "]" denotes an inclusive
|
||||
* end of the range and a round bracket "(" or ")" denotes an exclusive end of the
|
||||
* range. A range can also be unbounded by defining a a single {@link Version}. The
|
||||
* examples below make this clear.
|
||||
*
|
||||
* <ul>
|
||||
* <li>"[1.2.0.RELEASE,1.3.0.RELEASE)" version 1.2.0 and any version after
|
||||
* this, up to, but not including, version 1.3.0.</li>
|
||||
* <li>"(2.0.0.RELEASE,3.2.0.RELEASE]" any version after 2.0.0 up to and
|
||||
* including version 3.2.0.</li>
|
||||
* <li>"1.4.5.RELEASE", version 1.4.5 and all later versions.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.0
|
||||
*/
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
class VersionRange {
|
||||
|
||||
private static final String RANGE_REGEX = "(\\(|\\[)(.*),(.*)(\\)|\\])"
|
||||
|
||||
private Version lowerVersion
|
||||
private boolean lowerInclusive
|
||||
private Version higherVersion
|
||||
private boolean higherInclusive
|
||||
|
||||
/**
|
||||
* Specify if the {@link Version} matches this range. Returns {@code true}
|
||||
* if the version is contained within this range, {@code false} otherwise.
|
||||
*/
|
||||
boolean match(Version version) {
|
||||
Assert.notNull(version, "Version must not be null")
|
||||
def lower = lowerVersion.compareTo(version)
|
||||
if (lower > 0) {
|
||||
return false;
|
||||
} else if (!lowerInclusive && lower == 0) {
|
||||
return false;
|
||||
}
|
||||
if (higherVersion) {
|
||||
def higher = higherVersion.compareTo(version)
|
||||
if (higher < 0) {
|
||||
return false
|
||||
} else if (!higherInclusive && higher == 0) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the string representation of a {@link VersionRange}. Throws an
|
||||
* {@link InvalidVersionException} if the range could not be parsed.
|
||||
* @param text the range text
|
||||
* @return a VersionRange instance for the specified range text
|
||||
* @throws InvalidVersionException if the range text could not be parsed
|
||||
*/
|
||||
static VersionRange parse(String text) {
|
||||
Assert.notNull(text, "Text must not be null")
|
||||
def matcher = (text.trim() =~ RANGE_REGEX)
|
||||
if (!matcher.matches()) {
|
||||
// Try to read it as simple string
|
||||
Version version = Version.parse(text)
|
||||
return new VersionRange(lowerInclusive: true, lowerVersion: version)
|
||||
}
|
||||
VersionRange range = new VersionRange()
|
||||
range.lowerInclusive = matcher[0][1].equals('[')
|
||||
range.lowerVersion = Version.parse(matcher[0][2])
|
||||
range.higherVersion = Version.parse(matcher[0][3])
|
||||
range.higherInclusive = matcher[0][4].equals(']')
|
||||
range
|
||||
}
|
||||
|
||||
}
|
@ -18,6 +18,7 @@ package io.spring.initializr.web
|
||||
|
||||
import groovy.util.logging.Slf4j
|
||||
import io.spring.initializr.CommandLineHelpGenerator
|
||||
import io.spring.initializr.InitializrMetadataVersion
|
||||
import io.spring.initializr.ProjectGenerator
|
||||
import io.spring.initializr.ProjectRequest
|
||||
|
||||
@ -79,11 +80,20 @@ class MainController extends AbstractInitializrController {
|
||||
builder.body(commandLineHelpGenerator.generateGenericCapabilities(metadata, appUrl))
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/", produces = ["application/vnd.initializr.v2+json", "application/json"])
|
||||
ResponseEntity<String> serviceCapabilities() {
|
||||
@RequestMapping(value = "/", produces = ["application/vnd.initializr.v2.1+json", "application/json"])
|
||||
ResponseEntity<String> serviceCapabilitiesV21() {
|
||||
serviceCapabilitiesFor(InitializrMetadataVersion.V2_1)
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/", produces = ["application/vnd.initializr.v2+json"])
|
||||
ResponseEntity<String> serviceCapabilitiesV2() {
|
||||
serviceCapabilitiesFor(InitializrMetadataVersion.V2)
|
||||
}
|
||||
|
||||
private ResponseEntity<String> serviceCapabilitiesFor(InitializrMetadataVersion version) {
|
||||
String appUrl = ServletUriComponentsBuilder.fromCurrentServletMapping().build()
|
||||
def content = metadataProvider.get().generateJson(appUrl)
|
||||
return ResponseEntity.ok().contentType(META_DATA_V2).body(content)
|
||||
def content = metadataProvider.get().generateJson(version, appUrl)
|
||||
return ResponseEntity.ok().contentType(version.mediaType).body(content)
|
||||
}
|
||||
|
||||
@RequestMapping(value = '/', produces = 'text/html')
|
||||
|
@ -97,6 +97,16 @@ class InitializrMetadataTests {
|
||||
metadata.validateDependency(new InitializrMetadata.Dependency())
|
||||
}
|
||||
|
||||
@Test
|
||||
void invalidSpringBootRange() {
|
||||
def dependency = createDependency('web')
|
||||
dependency.versionRange = 'A.B.C'
|
||||
|
||||
thrown.expect(InvalidInitializrMetadataException)
|
||||
thrown.expectMessage('A.B.C')
|
||||
metadata.validateDependency(dependency)
|
||||
}
|
||||
|
||||
@Test
|
||||
void invalidIdFormatTooManyColons() {
|
||||
def dependency = createDependency('org.foo:bar:1.0:test:external')
|
||||
|
@ -95,6 +95,37 @@ class ProjectRequestTests {
|
||||
thrown.expect(InvalidProjectRequestException)
|
||||
thrown.expectMessage('org.foo:acme')
|
||||
request.resolve(metadata)
|
||||
assertEquals(1, request.resolvedDependencies.size())
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveDependencyInRange() {
|
||||
def request = new ProjectRequest()
|
||||
def dependency = createDependency('org.foo', 'bar', '1.2.0.RELEASE')
|
||||
dependency.versionRange = '[1.0.1.RELEASE, 1.2.0.RELEASE)'
|
||||
def metadata = InitializrMetadataBuilder.withDefaults()
|
||||
.addDependencyGroup('code', dependency).validateAndGet()
|
||||
|
||||
request.style << 'org.foo:bar'
|
||||
request.bootVersion = '1.1.2.RELEASE'
|
||||
request.resolve(metadata)
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveDependencyNotInRange() {
|
||||
def request = new ProjectRequest()
|
||||
def dependency = createDependency('org.foo', 'bar', '1.2.0.RELEASE')
|
||||
dependency.versionRange = '[1.0.1.RELEASE, 1.2.0.RELEASE)'
|
||||
def metadata = InitializrMetadataBuilder.withDefaults()
|
||||
.addDependencyGroup('code', dependency).validateAndGet()
|
||||
|
||||
request.style << 'org.foo:bar'
|
||||
request.bootVersion = '0.9.9.RELEASE'
|
||||
|
||||
thrown.expect(InvalidProjectRequestException)
|
||||
thrown.expectMessage('org.foo:bar')
|
||||
thrown.expectMessage('0.9.9.RELEASE')
|
||||
request.resolve(metadata)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -14,9 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.spring.initializr
|
||||
package io.spring.initializr.mapper
|
||||
|
||||
import groovy.json.JsonSlurper
|
||||
import io.spring.initializr.InitializrMetadata
|
||||
import io.spring.initializr.test.InitializrMetadataBuilder
|
||||
import org.junit.Test
|
||||
|
||||
@ -27,7 +28,7 @@ import static org.junit.Assert.assertEquals
|
||||
*/
|
||||
class InitializrMetadataJsonMapperTests {
|
||||
|
||||
private final InitializrMetadataJsonMapper jsonMapper = new InitializrMetadataJsonMapper()
|
||||
private final InitializrMetadataJsonMapper jsonMapper = new InitializrMetadataV21JsonMapper()
|
||||
private final JsonSlurper slurper = new JsonSlurper()
|
||||
|
||||
@Test
|
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2012-2015 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.spring.initializr.support
|
||||
|
||||
import org.hamcrest.BaseMatcher
|
||||
import org.hamcrest.Description
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.ExpectedException
|
||||
|
||||
import static org.hamcrest.core.IsNot.not
|
||||
import static org.junit.Assert.assertThat
|
||||
|
||||
/**
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class VersionRangeTests {
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none()
|
||||
|
||||
@Test
|
||||
void matchSimpleRange() {
|
||||
assertThat('1.2.0.RC3', match('[1.2.0.RC1,1.2.0.RC5]'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchSimpleRangeBefore() {
|
||||
assertThat('1.1.9.RC3', not(match('[1.2.0.RC1,1.2.0.RC5]')))
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchSimpleRangeAfter() {
|
||||
assertThat('1.2.0.RC6', not(match('[1.2.0.RC1,1.2.0.RC5]')))
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchInclusiveLowerRange() {
|
||||
assertThat('1.2.0.RC1', match('[1.2.0.RC1,1.2.0.RC5]'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchInclusiveHigherRange() {
|
||||
assertThat('1.2.0.RC5', match('[1.2.0.RC1,1.2.0.RC5]'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchExclusiveLowerRange() {
|
||||
assertThat('1.2.0.RC1', not(match('(1.2.0.RC1,1.2.0.RC5)')))
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchExclusiveHigherRange() {
|
||||
assertThat('1.2.0.RC5', not(match('[1.2.0.RC1,1.2.0.RC5)')))
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchUnboundedRangeEqual() {
|
||||
assertThat('1.2.0.RELEASE', match('1.2.0.RELEASE'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchUnboundedRangeAfter() {
|
||||
assertThat('2.2.0.RELEASE', match('1.2.0.RELEASE'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchUnboundedRangeBefore() {
|
||||
assertThat('1.1.9.RELEASE', not(match('1.2.0.RELEASE')))
|
||||
}
|
||||
|
||||
@Test
|
||||
void invalidRange() {
|
||||
thrown.expect(InvalidVersionException)
|
||||
VersionRange.parse("foo-bar")
|
||||
}
|
||||
|
||||
@Test
|
||||
void rangeWithSpaces() {
|
||||
assertThat('1.2.0.RC3', match('[ 1.2.0.RC1 , 1.2.0.RC5]'))
|
||||
}
|
||||
|
||||
|
||||
private static VersionRangeMatcher match(String range) {
|
||||
new VersionRangeMatcher(range)
|
||||
}
|
||||
|
||||
|
||||
static class VersionRangeMatcher extends BaseMatcher<String> {
|
||||
|
||||
private final VersionRange range;
|
||||
|
||||
VersionRangeMatcher(String text) {
|
||||
this.range = VersionRange.parse(text)
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean matches(Object item) {
|
||||
if (!item instanceof String) {
|
||||
return false;
|
||||
}
|
||||
return this.range.match(Version.parse(item))
|
||||
}
|
||||
|
||||
@Override
|
||||
void describeTo(Description description) {
|
||||
description.appendText(range)
|
||||
}
|
||||
}
|
||||
}
|
@ -130,7 +130,7 @@ class VersionTests {
|
||||
|
||||
@Test
|
||||
void parseInvalidVersion() {
|
||||
thrown.expect(IllegalArgumentException)
|
||||
thrown.expect(InvalidVersionException)
|
||||
parse('foo')
|
||||
}
|
||||
|
||||
@ -139,4 +139,9 @@ class VersionTests {
|
||||
assertNull safeParse('foo')
|
||||
}
|
||||
|
||||
@Test
|
||||
void parseVersionWithSpaces() {
|
||||
assertThat(parse(' 1.2.0.RC3 '), lessThan(parse('1.3.0.RELEASE')))
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,7 +19,9 @@ package io.spring.initializr.web
|
||||
import java.nio.charset.Charset
|
||||
|
||||
import groovy.json.JsonSlurper
|
||||
import io.spring.initializr.InitializrMetadataVersion
|
||||
import org.json.JSONObject
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import org.skyscreamer.jsonassert.JSONAssert
|
||||
import org.skyscreamer.jsonassert.JSONCompareMode
|
||||
@ -43,8 +45,7 @@ import static org.junit.Assert.*
|
||||
@ActiveProfiles('test-default')
|
||||
class MainControllerIntegrationTests extends AbstractInitializrControllerIntegrationTests {
|
||||
|
||||
private static final MediaType CURRENT_METADATA_MEDIA_TYPE =
|
||||
MediaType.parseMediaType('application/vnd.initializr.v2+json')
|
||||
private static final MediaType CURRENT_METADATA_MEDIA_TYPE = InitializrMetadataVersion.V2_1.mediaType
|
||||
|
||||
private final def slurper = new JsonSlurper()
|
||||
|
||||
@ -60,10 +61,27 @@ class MainControllerIntegrationTests extends AbstractInitializrControllerIntegra
|
||||
|
||||
@Test
|
||||
void simpleTgzProject() {
|
||||
downloadTgz('/starter.tgz?style=org.acme:bar').isJavaProject().isMavenProject()
|
||||
downloadTgz('/starter.tgz?style=org.acme:foo').isJavaProject().isMavenProject()
|
||||
.hasStaticAndTemplatesResources(false).pomAssert()
|
||||
.hasDependenciesCount(2)
|
||||
.hasDependency('org.acme', 'bar', '2.1.0')
|
||||
.hasDependency('org.acme', 'foo', '1.3.5')
|
||||
}
|
||||
|
||||
@Test
|
||||
void dependencyInRange() {
|
||||
downloadTgz('/starter.tgz?style=org.acme:biz&bootVersion=1.2.1.RELEASE').isJavaProject().isMavenProject()
|
||||
.hasStaticAndTemplatesResources(false).pomAssert()
|
||||
.hasDependenciesCount(2)
|
||||
.hasDependency('org.acme', 'biz', '1.3.5')
|
||||
}
|
||||
|
||||
@Test
|
||||
void dependencyNotInRange() {
|
||||
try {
|
||||
execute('/starter.tgz?style=org.acme:bur', byte[], null, null)
|
||||
} catch (HttpClientErrorException ex) {
|
||||
assertEquals HttpStatus.NOT_ACCEPTABLE, ex.statusCode
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -136,12 +154,34 @@ class MainControllerIntegrationTests extends AbstractInitializrControllerIntegra
|
||||
}
|
||||
|
||||
@Test
|
||||
void metadataWithCurrentAcceptHeader() {
|
||||
@Ignore("Need a comparator that does not care about the number of elements in an array")
|
||||
void currentMetadataCompatibleWithV2() {
|
||||
ResponseEntity<String> response = invokeHome(null, '*/*')
|
||||
validateMetadata(response, CURRENT_METADATA_MEDIA_TYPE, '2.0.0', JSONCompareMode.LENIENT)
|
||||
}
|
||||
|
||||
@Test
|
||||
void metadataWithV2AcceptHeader() {
|
||||
ResponseEntity<String> response = invokeHome(null, 'application/vnd.initializr.v2+json')
|
||||
validateMetadata(response, InitializrMetadataVersion.V2.mediaType, '2.0.0', JSONCompareMode.STRICT)
|
||||
}
|
||||
|
||||
@Test
|
||||
void metadataWithCurrentAcceptHeader() {
|
||||
ResponseEntity<String> response = invokeHome(null, 'application/vnd.initializr.v2.1+json')
|
||||
validateContentType(response, CURRENT_METADATA_MEDIA_TYPE)
|
||||
validateCurrentMetadata(new JSONObject(response.body))
|
||||
}
|
||||
|
||||
@Test
|
||||
void metadataWithUnknownAcceptHeader() {
|
||||
try {
|
||||
invokeHome(null, 'application/vnd.initializr.v5.4+json')
|
||||
} catch (HttpClientErrorException ex) {
|
||||
assertEquals HttpStatus.NOT_ACCEPTABLE, ex.statusCode
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void curlReceivesTextByDefault() {
|
||||
ResponseEntity<String> response = invokeHome('curl/1.2.4', "*/*")
|
||||
@ -210,13 +250,21 @@ class MainControllerIntegrationTests extends AbstractInitializrControllerIntegra
|
||||
validateCurrentMetadata(json)
|
||||
}
|
||||
|
||||
private void validateMetadata(ResponseEntity<String> response, MediaType mediaType,
|
||||
String version, JSONCompareMode compareMode) {
|
||||
validateContentType(response, mediaType)
|
||||
def json = new JSONObject(response.body)
|
||||
def expected = readJson(version)
|
||||
JSONAssert.assertEquals(expected, json, compareMode)
|
||||
}
|
||||
|
||||
private void validateCurrentMetadata(ResponseEntity<String> response) {
|
||||
validateContentType(response, CURRENT_METADATA_MEDIA_TYPE)
|
||||
validateCurrentMetadata(new JSONObject(response.body))
|
||||
}
|
||||
|
||||
private void validateCurrentMetadata(JSONObject json) {
|
||||
def expected = readJson('2.0.0')
|
||||
def expected = readJson('2.1.0')
|
||||
JSONAssert.assertEquals(expected, json, JSONCompareMode.STRICT)
|
||||
}
|
||||
|
||||
|
@ -101,8 +101,8 @@ class ProjectGenerationSmokeTests extends AbstractInitializrControllerIntegratio
|
||||
page.artifactId = 'foo-bar'
|
||||
page.name = 'My project'
|
||||
page.description = 'A description for my project'
|
||||
page.dependency('web')
|
||||
page.dependency('data-jpa')
|
||||
page.dependency('web').click()
|
||||
page.dependency('data-jpa').click()
|
||||
page.generateProject.click()
|
||||
at HomePage
|
||||
def projectAssert = zipProjectAssert(from('foo-bar.zip'))
|
||||
@ -126,8 +126,8 @@ class ProjectGenerationSmokeTests extends AbstractInitializrControllerIntegratio
|
||||
page.artifactId = 'groovy-project'
|
||||
page.name = 'My Groovy project'
|
||||
page.description = 'A description for my Groovy project'
|
||||
page.dependency('web')
|
||||
page.dependency('data-jpa')
|
||||
page.dependency('web').click()
|
||||
page.dependency('data-jpa').click()
|
||||
page.generateProject.click()
|
||||
at HomePage
|
||||
def projectAssert = zipProjectAssert(from('groovy-project.zip'))
|
||||
@ -147,7 +147,7 @@ class ProjectGenerationSmokeTests extends AbstractInitializrControllerIntegratio
|
||||
void createSimpleGradleProject() {
|
||||
toHome {
|
||||
page.type = 'gradle-project'
|
||||
page.dependency('data-jpa')
|
||||
page.dependency('data-jpa').click()
|
||||
page.generateProject.click()
|
||||
at HomePage
|
||||
def projectAssert = zipProjectAssert(from('demo.zip'))
|
||||
@ -177,7 +177,7 @@ class ProjectGenerationSmokeTests extends AbstractInitializrControllerIntegratio
|
||||
void createMavenBuild() {
|
||||
toHome {
|
||||
page.type = 'maven-build'
|
||||
page.dependency('data-jpa')
|
||||
page.dependency('data-jpa').click()
|
||||
page.artifactId = 'my-maven-project'
|
||||
page.generateProject.click()
|
||||
at HomePage
|
||||
@ -200,6 +200,35 @@ class ProjectGenerationSmokeTests extends AbstractInitializrControllerIntegratio
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void dependencyHiddenAccordingToRange() {
|
||||
toHome { // bur: [1.1.4.RELEASE,1.2.0.BUILD-SNAPSHOT)
|
||||
page.dependency('org.acme:bur').displayed == true
|
||||
|
||||
page.bootVersion = '1.0.2.RELEASE'
|
||||
page.dependency('org.acme:bur').displayed == false
|
||||
page.dependency('org.acme:biz').displayed == false
|
||||
page.bootVersion = '1.1.4.RELEASE'
|
||||
page.dependency('org.acme:bur').displayed == true
|
||||
page.dependency('org.acme:biz').displayed == false
|
||||
page.bootVersion = '1.2.0.BUILD-SNAPSHOT'
|
||||
page.dependency('org.acme:bur').displayed == false
|
||||
page.dependency('org.acme:biz').displayed == true
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void dependencyUncheckedWhenHidden() {
|
||||
toHome {
|
||||
page.dependency('org.acme:bur').value() == 'org.acme:bur'
|
||||
page.bootVersion = '1.0.2.RELEASE'
|
||||
page.dependency('org.acme:bur').displayed == false
|
||||
page.bootVersion = '1.1.4.RELEASE'
|
||||
page.dependency('org.acme:bur').displayed == true
|
||||
page.dependency('org.acme:bur').value() == false
|
||||
}
|
||||
}
|
||||
|
||||
private Browser toHome(Closure script) {
|
||||
browser.go("http://localhost:" + port + "/")
|
||||
browser.at HomePage
|
||||
|
@ -39,7 +39,7 @@ class HomePage extends Page {
|
||||
language { $('form').language() }
|
||||
|
||||
dependency { id ->
|
||||
$("form").find('input', type: "checkbox", name: "style", value: id).click()
|
||||
$("form").find('input', type: "checkbox", name: "style", value: id)
|
||||
}
|
||||
generateProject { $('form').find('button', name: 'generate-project') }
|
||||
|
||||
|
@ -27,6 +27,15 @@ initializr:
|
||||
- name: Bar
|
||||
id: org.acme:bar
|
||||
version: 2.1.0
|
||||
- name: Biz
|
||||
groupId: org.acme
|
||||
artifactId: biz
|
||||
version: 1.3.5
|
||||
versionRange: 1.2.0.BUILD-SNAPSHOT
|
||||
- name: Bur
|
||||
id: org.acme:bur
|
||||
version: 2.1.0
|
||||
versionRange: "[1.1.4.RELEASE,1.2.0.BUILD-SNAPSHOT)"
|
||||
types:
|
||||
- name: Maven POM
|
||||
id: maven-build
|
||||
|
196
initializr/src/test/resources/metadata/test-default-2.1.0.json
Normal file
196
initializr/src/test/resources/metadata/test-default-2.1.0.json
Normal file
@ -0,0 +1,196 @@
|
||||
{
|
||||
"_links": {
|
||||
"maven-build": {
|
||||
"href": "http://localhost:@port@/pom.xml?type=maven-build{&dependencies,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}",
|
||||
"templated": true
|
||||
},
|
||||
"maven-project": {
|
||||
"href": "http://localhost:@port@/starter.zip?type=maven-project{&dependencies,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}",
|
||||
"templated": true
|
||||
},
|
||||
"gradle-build": {
|
||||
"href": "http://localhost:@port@/build.gradle?type=gradle-build{&dependencies,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}",
|
||||
"templated": true
|
||||
},
|
||||
"gradle-project": {
|
||||
"href": "http://localhost:@port@/starter.zip?type=gradle-project{&dependencies,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}",
|
||||
"templated": true
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"type": "hierarchical-multi-select",
|
||||
"values": [
|
||||
{
|
||||
"name": "Core",
|
||||
"values": [
|
||||
{
|
||||
"id": "web",
|
||||
"name": "Web",
|
||||
"description": "Web dependency description"
|
||||
},
|
||||
{
|
||||
"id": "security",
|
||||
"name": "Security"
|
||||
},
|
||||
{
|
||||
"id": "data-jpa",
|
||||
"name": "Data JPA"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Other",
|
||||
"values": [
|
||||
{
|
||||
"id": "org.acme:foo",
|
||||
"name": "Foo"
|
||||
},
|
||||
{
|
||||
"id": "org.acme:bar",
|
||||
"name": "Bar"
|
||||
},
|
||||
{
|
||||
"id": "org.acme:biz",
|
||||
"name": "Biz",
|
||||
"versionRange": "1.2.0.BUILD-SNAPSHOT"
|
||||
},
|
||||
{
|
||||
"id": "org.acme:bur",
|
||||
"name": "Bur",
|
||||
"versionRange": "[1.1.4.RELEASE,1.2.0.BUILD-SNAPSHOT)"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "action",
|
||||
"default": "maven-project",
|
||||
"values": [
|
||||
{
|
||||
"id": "maven-build",
|
||||
"name": "Maven POM",
|
||||
"action": "/pom.xml",
|
||||
"tags": {
|
||||
"build": "maven",
|
||||
"format": "build"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "maven-project",
|
||||
"name": "Maven Project",
|
||||
"action": "/starter.zip",
|
||||
"tags": {
|
||||
"build": "maven",
|
||||
"format": "project"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "gradle-build",
|
||||
"name": "Gradle Config",
|
||||
"action": "/build.gradle",
|
||||
"tags": {
|
||||
"build": "gradle",
|
||||
"format": "build"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "gradle-project",
|
||||
"name": "Gradle Project",
|
||||
"action": "/starter.zip",
|
||||
"tags": {
|
||||
"build": "gradle",
|
||||
"format": "project"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"packaging": {
|
||||
"type": "single-select",
|
||||
"default": "jar",
|
||||
"values": [
|
||||
{
|
||||
"id": "jar",
|
||||
"name": "Jar"
|
||||
},
|
||||
{
|
||||
"id": "war",
|
||||
"name": "War"
|
||||
}
|
||||
]
|
||||
},
|
||||
"javaVersion": {
|
||||
"type": "single-select",
|
||||
"default": "1.7",
|
||||
"values": [
|
||||
{
|
||||
"id": "1.6",
|
||||
"name": "1.6"
|
||||
},
|
||||
{
|
||||
"id": "1.7",
|
||||
"name": "1.7"
|
||||
},
|
||||
{
|
||||
"id": "1.8",
|
||||
"name": "1.8"
|
||||
}
|
||||
]
|
||||
},
|
||||
"language": {
|
||||
"type": "single-select",
|
||||
"default": "java",
|
||||
"values": [
|
||||
{
|
||||
"id": "groovy",
|
||||
"name": "Groovy"
|
||||
},
|
||||
{
|
||||
"id": "java",
|
||||
"name": "Java"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bootVersion": {
|
||||
"type": "single-select",
|
||||
"default": "1.1.4.RELEASE",
|
||||
"values": [
|
||||
{
|
||||
"id": "1.2.0.BUILD-SNAPSHOT",
|
||||
"name": "Latest SNAPSHOT"
|
||||
},
|
||||
{
|
||||
"id": "1.1.4.RELEASE",
|
||||
"name": "1.1.4"
|
||||
},
|
||||
{
|
||||
"id": "1.0.2.RELEASE",
|
||||
"name": "1.0.2"
|
||||
}
|
||||
]
|
||||
},
|
||||
"groupId": {
|
||||
"type": "text",
|
||||
"default": "org.test"
|
||||
},
|
||||
"artifactId": {
|
||||
"type": "text",
|
||||
"default": "demo"
|
||||
},
|
||||
"version": {
|
||||
"type": "text",
|
||||
"default": "0.0.1-SNAPSHOT"
|
||||
},
|
||||
"name": {
|
||||
"type": "text",
|
||||
"default": "demo"
|
||||
},
|
||||
"description": {
|
||||
"type": "text",
|
||||
"default": "Demo project for Spring Boot"
|
||||
},
|
||||
"packageName": {
|
||||
"type": "text",
|
||||
"default": "demo"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user