From 496520e990e13cdf1dab0bb2c7a0cb56c8c50843 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 18 Nov 2015 11:47:53 +0000 Subject: [PATCH] Expose dependencies meta-data Register an additional endpoint at `/dependencies` that returns the necessary information about the registered dependencies for a Spring Boot version. If the `bootVersion` request parameter is not specified, the default Spring Boot version is used. The json content contains the artifact coordinates as well as the necesasry BOM or repository to add. This information should be useful enough for any tool to add additional dependencies to an existing project or create one from scratch. Closes gh-140 --- .../config/InitializrAutoConfiguration.groovy | 17 +- .../DependencyMetadataJsonMapper.groovy | 34 ++++ .../DependencyMetadataV21JsonMapper.groovy | 85 +++++++++ .../InitializrMetadataV21JsonMapper.groovy | 31 +++- .../mapper/InitializrMetadataVersion.groovy | 3 +- .../metadata/BillOfMaterials.groovy | 3 +- .../initializr/metadata/Dependency.groovy | 10 ++ .../metadata/DependencyMetadata.groovy | 45 +++++ .../DependencyMetadataProvider.groovy | 33 ++++ .../metadata/InitializrMetadata.groovy | 25 ++- .../initializr/metadata/Repository.groovy | 5 + .../DefaultDependencyMetadataProvider.groovy | 70 ++++++++ .../io/spring/initializr/util/Version.groovy | 3 +- .../initializr/web/MainController.groovy | 26 ++- .../DependencyMetadataJsonMapperTests.groovy | 56 ++++++ .../metadata/InitializrMetadataTests.groovy | 30 ++++ ...aultDependencyMetadataProviderTests.groovy | 166 ++++++++++++++++++ .../MainControllerDependenciesTests.groovy | 60 +++++++ .../web/UiControllerIntegrationTests.groovy | 2 +- .../resources/application-test-default.yml | 20 +++ .../metadata/config/test-default.json | 37 +++- .../dependencies/test-dependencies-1.1.4.json | 61 +++++++ .../dependencies/test-dependencies-1.2.1.json | 61 +++++++ .../metadata/test-default-2.1.0.json | 4 + .../test-dependencies-1.1.2.json | 0 .../test-dependencies-all.json | 0 26 files changed, 871 insertions(+), 16 deletions(-) create mode 100644 initializr/src/main/groovy/io/spring/initializr/mapper/DependencyMetadataJsonMapper.groovy create mode 100644 initializr/src/main/groovy/io/spring/initializr/mapper/DependencyMetadataV21JsonMapper.groovy create mode 100644 initializr/src/main/groovy/io/spring/initializr/metadata/DependencyMetadata.groovy create mode 100644 initializr/src/main/groovy/io/spring/initializr/metadata/DependencyMetadataProvider.groovy create mode 100644 initializr/src/main/groovy/io/spring/initializr/support/DefaultDependencyMetadataProvider.groovy create mode 100644 initializr/src/test/groovy/io/spring/initializr/mapper/DependencyMetadataJsonMapperTests.groovy create mode 100644 initializr/src/test/groovy/io/spring/initializr/support/DefaultDependencyMetadataProviderTests.groovy create mode 100644 initializr/src/test/groovy/io/spring/initializr/web/MainControllerDependenciesTests.groovy create mode 100644 initializr/src/test/resources/metadata/dependencies/test-dependencies-1.1.4.json create mode 100644 initializr/src/test/resources/metadata/dependencies/test-dependencies-1.2.1.json rename initializr/src/test/resources/metadata/{dependencies => ui}/test-dependencies-1.1.2.json (100%) rename initializr/src/test/resources/metadata/{dependencies => ui}/test-dependencies-all.json (100%) diff --git a/initializr/src/main/groovy/io/spring/initializr/config/InitializrAutoConfiguration.groovy b/initializr/src/main/groovy/io/spring/initializr/config/InitializrAutoConfiguration.groovy index cba940f3..8c6b6433 100644 --- a/initializr/src/main/groovy/io/spring/initializr/config/InitializrAutoConfiguration.groovy +++ b/initializr/src/main/groovy/io/spring/initializr/config/InitializrAutoConfiguration.groovy @@ -22,9 +22,11 @@ import com.google.common.cache.CacheBuilder import io.spring.initializr.generator.ProjectGenerationMetricsListener import io.spring.initializr.generator.ProjectGenerator import io.spring.initializr.generator.ProjectResourceLocator +import io.spring.initializr.metadata.DependencyMetadataProvider import io.spring.initializr.metadata.InitializrMetadataBuilder import io.spring.initializr.metadata.InitializrMetadataProvider import io.spring.initializr.metadata.InitializrProperties +import io.spring.initializr.support.DefaultDependencyMetadataProvider import io.spring.initializr.support.DefaultInitializrMetadataProvider import io.spring.initializr.web.MainController import io.spring.initializr.web.UiController @@ -67,19 +69,19 @@ class InitializrAutoConfiguration { } @Bean - @ConditionalOnMissingBean(MainController) + @ConditionalOnMissingBean MainController initializrMainController() { new MainController() } @Bean - @ConditionalOnMissingBean(UiController) + @ConditionalOnMissingBean UiController initializrUiController() { new UiController() } @Bean - @ConditionalOnMissingBean(ProjectGenerator) + @ConditionalOnMissingBean ProjectGenerator projectGenerator() { def generator = new ProjectGenerator() generator.listeners << metricsListener() @@ -98,17 +100,24 @@ class InitializrAutoConfiguration { new DefaultInitializrMetadataProvider(metadata) } + @Bean + @ConditionalOnMissingBean + DependencyMetadataProvider dependencyMetadataProvider() { + new DefaultDependencyMetadataProvider() + } + @Bean ProjectGenerationMetricsListener metricsListener() { new ProjectGenerationMetricsListener(counterService) } @Bean - @ConditionalOnMissingBean(CacheManager) + @ConditionalOnMissingBean CacheManager cacheManager() { def cacheManager = new SimpleCacheManager() cacheManager.caches = Arrays.asList( createConcurrentMapCache(600, 'initializr'), + new ConcurrentMapCache('dependency-metadata'), new ConcurrentMapCache("project-resources")) cacheManager } diff --git a/initializr/src/main/groovy/io/spring/initializr/mapper/DependencyMetadataJsonMapper.groovy b/initializr/src/main/groovy/io/spring/initializr/mapper/DependencyMetadataJsonMapper.groovy new file mode 100644 index 00000000..34084a36 --- /dev/null +++ b/initializr/src/main/groovy/io/spring/initializr/mapper/DependencyMetadataJsonMapper.groovy @@ -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.metadata.DependencyMetadata + +/** + * Generate a JSON representation of a set of dependencies. + * + * @author Stephane Nicoll + * @since 1.0 + */ +interface DependencyMetadataJsonMapper { + + /** + * Write a json representation of the specified meta-data. + */ + String write(DependencyMetadata metadata); + +} diff --git a/initializr/src/main/groovy/io/spring/initializr/mapper/DependencyMetadataV21JsonMapper.groovy b/initializr/src/main/groovy/io/spring/initializr/mapper/DependencyMetadataV21JsonMapper.groovy new file mode 100644 index 00000000..ea99869e --- /dev/null +++ b/initializr/src/main/groovy/io/spring/initializr/mapper/DependencyMetadataV21JsonMapper.groovy @@ -0,0 +1,85 @@ +/* + * 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 groovy.json.JsonBuilder +import io.spring.initializr.metadata.BillOfMaterials +import io.spring.initializr.metadata.Dependency +import io.spring.initializr.metadata.DependencyMetadata +import io.spring.initializr.metadata.Repository + +/** + * A {@link DependencyMetadataJsonMapper} handling the meta-data format for v2.1. + * + * @author Stephane Nicoll + * @since 1.0 + */ +class DependencyMetadataV21JsonMapper implements DependencyMetadataJsonMapper { + + @Override + String write(DependencyMetadata metadata) { + JsonBuilder json = new JsonBuilder() + json { + bootVersion metadata.bootVersion.toString() + dependencies metadata.dependencies.collectEntries { id, d -> + [id, mapDependency(d)] + } + repositories metadata.repositories.collectEntries { id, r -> [id, mapRepository(r)] } + boms metadata.boms.collectEntries { id, b -> [id, mapBom(b)] } + } + json.toString() + } + + private static mapDependency(Dependency dep) { + def result = [:] + result.groupId = dep.groupId + result.artifactId = dep.artifactId + if (dep.version) { + result.version = dep.version + } + result.scope = dep.scope + if (dep.bom) { + result.bom = dep.bom + } + if (dep.repository) { + result.repository = dep.repository + } + result + } + + private static mapRepository(Repository repo) { + def result = [:] + result.name = repo.name + result.url = repo.url + result.snapshotEnabled = repo.snapshotsEnabled + result + } + + private static mapBom(BillOfMaterials bom) { + def result = [:] + result.groupId = bom.groupId + result.artifactId = bom.artifactId + if (bom.version) { + result.version = bom.version + } + if (bom.repositories) { + result.repositories = bom.repositories + } + result + } + +} diff --git a/initializr/src/main/groovy/io/spring/initializr/mapper/InitializrMetadataV21JsonMapper.groovy b/initializr/src/main/groovy/io/spring/initializr/mapper/InitializrMetadataV21JsonMapper.groovy index e8c11587..e96a6679 100644 --- a/initializr/src/main/groovy/io/spring/initializr/mapper/InitializrMetadataV21JsonMapper.groovy +++ b/initializr/src/main/groovy/io/spring/initializr/mapper/InitializrMetadataV21JsonMapper.groovy @@ -16,17 +16,37 @@ package io.spring.initializr.mapper +import org.springframework.hateoas.TemplateVariable +import org.springframework.hateoas.TemplateVariables +import org.springframework.hateoas.UriTemplate + /** * A {@link InitializrMetadataJsonMapper} handling the meta-data format for v2.1 *

* Version 2.1 brings the 'versionRange' attribute for a dependency to restrict - * the Spring Boot versions that can be used against it. + * the Spring Boot versions that can be used against it. That version also adds + * an additional `dependencies` endpoint. * * @author Stephane Nicoll * @since 1.0 */ class InitializrMetadataV21JsonMapper extends InitializrMetadataV2JsonMapper { + private final TemplateVariables dependenciesVariables + + InitializrMetadataV21JsonMapper() { + this.dependenciesVariables = new TemplateVariables( + new TemplateVariable('bootVersion', TemplateVariable.VariableType.REQUEST_PARAM) + ) + } + + @Override + protected links(parent, types, appUrl) { + def links = super.links(parent, types, appUrl) + links['dependencies'] = dependenciesLink(appUrl) + links + } + @Override protected mapDependency(dependency) { def content = mapValue(dependency) @@ -35,4 +55,13 @@ class InitializrMetadataV21JsonMapper extends InitializrMetadataV2JsonMapper { } content } + + private dependenciesLink(appUrl) { + String uri = appUrl != null ? appUrl + '/dependencies' : '/dependencies' + UriTemplate uriTemplate = new UriTemplate(uri, this.dependenciesVariables) + def result = [:] + result.href = uriTemplate.toString() + result.templated = true + result + } } diff --git a/initializr/src/main/groovy/io/spring/initializr/mapper/InitializrMetadataVersion.groovy b/initializr/src/main/groovy/io/spring/initializr/mapper/InitializrMetadataVersion.groovy index dfe8bbef..c9d986d9 100644 --- a/initializr/src/main/groovy/io/spring/initializr/mapper/InitializrMetadataVersion.groovy +++ b/initializr/src/main/groovy/io/spring/initializr/mapper/InitializrMetadataVersion.groovy @@ -33,7 +33,8 @@ enum InitializrMetadataVersion { /** * Add 'versionRange' attribute to any dependency to specify which - * Spring Boot versions are compatible with it. + * Spring Boot versions are compatible with it. Also provide a + * separate 'dependencies' endpoint to query dependencies meta-data. */ V2_1('application/vnd.initializr.v2.1+json') diff --git a/initializr/src/main/groovy/io/spring/initializr/metadata/BillOfMaterials.groovy b/initializr/src/main/groovy/io/spring/initializr/metadata/BillOfMaterials.groovy index 38ecdfd1..a00e0162 100644 --- a/initializr/src/main/groovy/io/spring/initializr/metadata/BillOfMaterials.groovy +++ b/initializr/src/main/groovy/io/spring/initializr/metadata/BillOfMaterials.groovy @@ -29,7 +29,7 @@ import io.spring.initializr.util.VersionRange * @author Stephane Nicoll * @since 1.0 */ -@ToString(ignoreNulls = true, includePackage = false) +@ToString(ignoreNulls = true, excludes = 'mappings', includePackage = false) @JsonInclude(JsonInclude.Include.NON_NULL) class BillOfMaterials { @@ -79,6 +79,7 @@ class BillOfMaterials { throw new IllegalStateException("No suitable mapping was found for $this and version $bootVersion") } + @ToString(ignoreNulls = true, includePackage = false) static class Mapping { String versionRange diff --git a/initializr/src/main/groovy/io/spring/initializr/metadata/Dependency.groovy b/initializr/src/main/groovy/io/spring/initializr/metadata/Dependency.groovy index b3620d24..e0d2b414 100644 --- a/initializr/src/main/groovy/io/spring/initializr/metadata/Dependency.groovy +++ b/initializr/src/main/groovy/io/spring/initializr/metadata/Dependency.groovy @@ -179,6 +179,16 @@ class Dependency extends MetadataElement { return this } + /** + * Specify if this dependency is available for the specified Spring Boot version. + */ + boolean match(Version version) { + if (versionRange) { + return VersionRange.parse(versionRange).match(version) + } + true + } + /** * Generate an id using the groupId and artifactId */ diff --git a/initializr/src/main/groovy/io/spring/initializr/metadata/DependencyMetadata.groovy b/initializr/src/main/groovy/io/spring/initializr/metadata/DependencyMetadata.groovy new file mode 100644 index 00000000..c8f9ec01 --- /dev/null +++ b/initializr/src/main/groovy/io/spring/initializr/metadata/DependencyMetadata.groovy @@ -0,0 +1,45 @@ +/* + * 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.metadata + +import io.spring.initializr.util.Version + +/** + * Dependency meta-data for a given spring boot {@link Version}. + * + * @author Stephane Nicoll + * @since 1.0 + */ +class DependencyMetadata { + + final Version bootVersion + + final Map dependencies + + final Map repositories + + final Map boms + + DependencyMetadata(Version bootVersion, Map dependencies, + Map repositories, Map boms) { + this.bootVersion = bootVersion + this.dependencies = dependencies + this.repositories = repositories + this.boms = boms + } + +} diff --git a/initializr/src/main/groovy/io/spring/initializr/metadata/DependencyMetadataProvider.groovy b/initializr/src/main/groovy/io/spring/initializr/metadata/DependencyMetadataProvider.groovy new file mode 100644 index 00000000..50b57ae2 --- /dev/null +++ b/initializr/src/main/groovy/io/spring/initializr/metadata/DependencyMetadataProvider.groovy @@ -0,0 +1,33 @@ +/* + * 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.metadata + +import io.spring.initializr.util.Version + +/** + * Provide the {@link DependencyMetadata} for a given spring boot version. + * + * @author Stephane Nicoll + */ +interface DependencyMetadataProvider { + + /** + * Return the dependency metadata to use for the specified {@code bootVersion}. + */ + DependencyMetadata get(InitializrMetadata metadata, Version bootVersion) + +} \ No newline at end of file diff --git a/initializr/src/main/groovy/io/spring/initializr/metadata/InitializrMetadata.groovy b/initializr/src/main/groovy/io/spring/initializr/metadata/InitializrMetadata.groovy index e0c55791..92e7cffb 100644 --- a/initializr/src/main/groovy/io/spring/initializr/metadata/InitializrMetadata.groovy +++ b/initializr/src/main/groovy/io/spring/initializr/metadata/InitializrMetadata.groovy @@ -15,6 +15,7 @@ */ package io.spring.initializr.metadata + /** * Meta-data used to generate a project. * @@ -44,7 +45,7 @@ class InitializrMetadata { final TextCapability name = new TextCapability('name', 'Name', 'project name (infer application name)') - final TextCapability description = new TextCapability('description', 'Description', 'project description' ) + final TextCapability description = new TextCapability('description', 'Description', 'project description') final TextCapability groupId = new TextCapability('groupId', 'Group', 'project coordinates') @@ -89,18 +90,36 @@ class InitializrMetadata { this.configuration.validate() dependencies.validate() - for (Dependency dependency : dependencies.all) { + def repositories = configuration.env.repositories + dependencies.all.forEach { dependency -> def boms = configuration.env.boms if (dependency.bom && !boms[dependency.bom]) { throw new InvalidInitializrMetadataException("Dependency $dependency " + "defines an invalid BOM id $dependency.bom, available boms $boms") } - def repositories = configuration.env.repositories + if (dependency.repository && !repositories[dependency.repository]) { throw new InvalidInitializrMetadataException("Dependency $dependency " + "defines an invalid repository id $dependency.repository, available repositores $repositories") } } + configuration.env.boms.values().forEach { bom -> + bom.repositories.forEach { r -> + if (!repositories[r]) { + throw new InvalidInitializrMetadataException("$bom " + + "defines an invalid repository id $r, available repositores $repositories") + } + } + bom.mappings.forEach{ m -> + m.repositories.forEach { r -> + if (!repositories[r]) { + throw new InvalidInitializrMetadataException("$m of $bom " + + "defines an invalid repository id $r, available repositores $repositories") + } + } + } + } + } /** diff --git a/initializr/src/main/groovy/io/spring/initializr/metadata/Repository.groovy b/initializr/src/main/groovy/io/spring/initializr/metadata/Repository.groovy index fb04122f..bb411579 100644 --- a/initializr/src/main/groovy/io/spring/initializr/metadata/Repository.groovy +++ b/initializr/src/main/groovy/io/spring/initializr/metadata/Repository.groovy @@ -16,6 +16,9 @@ package io.spring.initializr.metadata +import groovy.transform.EqualsAndHashCode +import groovy.transform.ToString + /** * Define a repository to be represented in the generated project * if a dependency refers to it. @@ -23,6 +26,8 @@ package io.spring.initializr.metadata * @author Stephane Nicoll * @since 1.0 */ +@EqualsAndHashCode +@ToString(includePackage = false) class Repository { String name diff --git a/initializr/src/main/groovy/io/spring/initializr/support/DefaultDependencyMetadataProvider.groovy b/initializr/src/main/groovy/io/spring/initializr/support/DefaultDependencyMetadataProvider.groovy new file mode 100644 index 00000000..2ccb0d30 --- /dev/null +++ b/initializr/src/main/groovy/io/spring/initializr/support/DefaultDependencyMetadataProvider.groovy @@ -0,0 +1,70 @@ +/* + * 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 io.spring.initializr.metadata.BillOfMaterials +import io.spring.initializr.metadata.Dependency +import io.spring.initializr.metadata.DependencyMetadata +import io.spring.initializr.metadata.DependencyMetadataProvider +import io.spring.initializr.metadata.InitializrMetadata +import io.spring.initializr.metadata.Repository +import io.spring.initializr.util.Version + +import org.springframework.cache.annotation.Cacheable + +/** + * A default {@link DependencyMetadataProvider} implementation. + * + * @author Stephane Nicoll + * @since 1.0 + */ +class DefaultDependencyMetadataProvider implements DependencyMetadataProvider { + + @Override + @Cacheable(cacheNames = "dependency-metadata", key = "#p1") + DependencyMetadata get(InitializrMetadata metadata, Version bootVersion) { + Map dependencies = [:] + metadata.dependencies.getAll().forEach { d -> + if (d.match(bootVersion)) { + dependencies[d.id] = d.resolve(bootVersion) + } + } + + Map repositories = [:] + dependencies.values().forEach { d -> + if (d.repository) { + repositories[d.repository] = metadata.configuration.env.repositories[d.repository] + } + } + + Map boms = [:] + dependencies.values().forEach { d -> + if (d.bom) { + boms[d.bom] = metadata.configuration.env.boms.get(d.bom).resolve(bootVersion) + } + } + // Each resolved bom may require additional repositories + boms.values().forEach { b -> + b.repositories.forEach { id -> + repositories[id] = metadata.configuration.env.repositories[id] + } + } + + return new DependencyMetadata(bootVersion, dependencies, repositories, boms) + } + +} diff --git a/initializr/src/main/groovy/io/spring/initializr/util/Version.groovy b/initializr/src/main/groovy/io/spring/initializr/util/Version.groovy index 9e017236..48333aa1 100644 --- a/initializr/src/main/groovy/io/spring/initializr/util/Version.groovy +++ b/initializr/src/main/groovy/io/spring/initializr/util/Version.groovy @@ -37,7 +37,8 @@ import org.springframework.util.Assert * @since 1.0 */ @EqualsAndHashCode -class Version implements Comparable { +@SuppressWarnings("serial") +final class Version implements Serializable, Comparable { private static final String VERSION_REGEX = '^(\\d+)\\.(\\d+)\\.(\\d+)(?:\\.([^0-9]+)(\\d+)?)?$' diff --git a/initializr/src/main/groovy/io/spring/initializr/web/MainController.groovy b/initializr/src/main/groovy/io/spring/initializr/web/MainController.groovy index ccba3016..3a0a52e9 100644 --- a/initializr/src/main/groovy/io/spring/initializr/web/MainController.groovy +++ b/initializr/src/main/groovy/io/spring/initializr/web/MainController.groovy @@ -21,13 +21,16 @@ import java.util.concurrent.TimeUnit import groovy.util.logging.Slf4j import io.spring.initializr.generator.CommandLineHelpGenerator +import io.spring.initializr.generator.ProjectGenerator +import io.spring.initializr.generator.ProjectRequest +import io.spring.initializr.mapper.DependencyMetadataV21JsonMapper import io.spring.initializr.mapper.InitializrMetadataJsonMapper import io.spring.initializr.mapper.InitializrMetadataV21JsonMapper import io.spring.initializr.mapper.InitializrMetadataV2JsonMapper import io.spring.initializr.mapper.InitializrMetadataVersion -import io.spring.initializr.generator.ProjectGenerator -import io.spring.initializr.generator.ProjectRequest +import io.spring.initializr.metadata.DependencyMetadataProvider import io.spring.initializr.metadata.InitializrMetadata +import io.spring.initializr.util.Version import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.CacheControl @@ -40,6 +43,7 @@ import org.springframework.util.DigestUtils import org.springframework.web.bind.annotation.ModelAttribute import org.springframework.web.bind.annotation.RequestHeader import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.ResponseBody /** @@ -60,6 +64,9 @@ class MainController extends AbstractInitializrController { @Autowired private ProjectGenerator projectGenerator + @Autowired + private DependencyMetadataProvider dependencyMetadataProvider + private CommandLineHelpGenerator commandLineHelpGenerator = new CommandLineHelpGenerator() @@ -140,6 +147,21 @@ class MainController extends AbstractInitializrController { } } + @RequestMapping(value = "/dependencies", produces = ["application/vnd.initializr.v2.1+json", "application/json"]) + ResponseEntity dependenciesV21(@RequestParam(required = false) String bootVersion) { + dependenciesFor(InitializrMetadataVersion.V2_1, bootVersion) + } + + private ResponseEntity dependenciesFor(InitializrMetadataVersion version, String bootVersion) { + def metadata = metadataProvider.get() + Version v = bootVersion != null ? Version.parse(bootVersion) : + Version.parse(metadata.bootVersions.getDefault().id); + def dependencyMetadata = dependencyMetadataProvider.get(metadata, v) + def content = new DependencyMetadataV21JsonMapper().write(dependencyMetadata) + return ResponseEntity.ok().contentType(version.mediaType).eTag(createUniqueId(content)) + .cacheControl(CacheControl.maxAge(7, TimeUnit.DAYS)).body(content) + } + @RequestMapping(value = '/', produces = 'text/html') @ResponseBody String home() { diff --git a/initializr/src/test/groovy/io/spring/initializr/mapper/DependencyMetadataJsonMapperTests.groovy b/initializr/src/test/groovy/io/spring/initializr/mapper/DependencyMetadataJsonMapperTests.groovy new file mode 100644 index 00000000..4e441853 --- /dev/null +++ b/initializr/src/test/groovy/io/spring/initializr/mapper/DependencyMetadataJsonMapperTests.groovy @@ -0,0 +1,56 @@ +/* + * 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 groovy.json.JsonSlurper +import io.spring.initializr.metadata.BillOfMaterials +import io.spring.initializr.metadata.Dependency +import io.spring.initializr.metadata.DependencyMetadata +import io.spring.initializr.metadata.Repository +import io.spring.initializr.util.Version +import org.junit.Test + +import static org.junit.Assert.* + +/** + * @author Stephane Nicoll + */ +class DependencyMetadataJsonMapperTests { + + private final DependencyMetadataJsonMapper mapper = new DependencyMetadataV21JsonMapper() + private final JsonSlurper slurper = new JsonSlurper() + + @Test + void mapDependency() { + Dependency d = new Dependency(id: 'foo', groupId: 'org.foo', artifactId: 'foo', + repository: 'my-repo', bom: 'my-bom') + Repository repository = new Repository(name: 'foo-repo', + url: new URL('http://example.com/foo')) + BillOfMaterials bom = new BillOfMaterials('groupId': 'org.foo', + artifactId: 'foo-bom', version: '1.0.0.RELEASE') + DependencyMetadata metadata = new DependencyMetadata(Version.parse('1.2.0.RELEASE'), + [(d.id): d], ['repo-id': repository], ['bom-id': bom]) + def content = slurper.parseText(mapper.write(metadata)) + println content + assertEquals 'my-bom', content.dependencies['foo'].bom + assertEquals 'my-repo', content.dependencies['foo'].repository + assertEquals 'foo-repo', content.repositories['repo-id'].name + assertEquals 'foo-bom', content.boms['bom-id'].artifactId + assertEquals '1.0.0.RELEASE', content.boms['bom-id'].version + } + +} diff --git a/initializr/src/test/groovy/io/spring/initializr/metadata/InitializrMetadataTests.groovy b/initializr/src/test/groovy/io/spring/initializr/metadata/InitializrMetadataTests.groovy index daedf329..15cafed8 100644 --- a/initializr/src/test/groovy/io/spring/initializr/metadata/InitializrMetadataTests.groovy +++ b/initializr/src/test/groovy/io/spring/initializr/metadata/InitializrMetadataTests.groovy @@ -68,6 +68,20 @@ class InitializrMetadataTests { builder.build() } + @Test + void invalidBomUnknownRepository() { + def bom = new BillOfMaterials(groupId: 'org.acme', artifactId: 'foo-bom', + version: '1.0.0.RELEASE', repositories: ['foo-repo']) + + InitializrMetadataTestBuilder builder = InitializrMetadataTestBuilder + .withDefaults().addBom('foo-bom', bom) + + thrown.expect(InvalidInitializrMetadataException) + thrown.expectMessage("invalid repository id foo-repo") + thrown.expectMessage("foo-bom") + builder.build() + } + @Test void invalidBomVersionRangeMapping() { def bom = new BillOfMaterials(groupId: 'org.acme', artifactId: 'foo-bom') @@ -83,4 +97,20 @@ class InitializrMetadataTests { builder.build() } + @Test + void invalidBomVersionRangeMappingUnknownRepo() { + def bom = new BillOfMaterials(groupId: 'org.acme', artifactId: 'foo-bom') + bom.mappings << new BillOfMaterials.Mapping(versionRange: '[1.0.0.RELEASE,1.3.0.M1)', version: '1.0.0') + bom.mappings << new BillOfMaterials.Mapping(versionRange: '1.3.0.M2', version: '1.2.0', repositories: ['foo-repo']) + + InitializrMetadataTestBuilder builder = InitializrMetadataTestBuilder + .withDefaults().addBom('foo-bom', bom) + + thrown.expect(InvalidInitializrMetadataException) + thrown.expectMessage("invalid repository id foo-repo") + thrown.expectMessage('1.3.0.M2') + thrown.expectMessage("foo-bom") + builder.build() + } + } diff --git a/initializr/src/test/groovy/io/spring/initializr/support/DefaultDependencyMetadataProviderTests.groovy b/initializr/src/test/groovy/io/spring/initializr/support/DefaultDependencyMetadataProviderTests.groovy new file mode 100644 index 00000000..1971bcb3 --- /dev/null +++ b/initializr/src/test/groovy/io/spring/initializr/support/DefaultDependencyMetadataProviderTests.groovy @@ -0,0 +1,166 @@ +/* + * 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 io.spring.initializr.metadata.BillOfMaterials +import io.spring.initializr.metadata.Dependency +import io.spring.initializr.metadata.DependencyMetadata +import io.spring.initializr.metadata.DependencyMetadataProvider +import io.spring.initializr.test.InitializrMetadataTestBuilder +import io.spring.initializr.util.Version +import org.junit.Test + +import static org.junit.Assert.assertEquals +import static org.junit.Assert.assertSame; + +/** + * @author Stephane Nicoll + */ +class DefaultDependencyMetadataProviderTests { + + private final DependencyMetadataProvider provider = new DefaultDependencyMetadataProvider() + + @Test + void filterDependencies() { + def first = new Dependency(id: 'first', groupId: 'org.foo', artifactId: 'first', + versionRange: '1.1.4.RELEASE') + def second = new Dependency(id: 'second', groupId: 'org.foo', artifactId: 'second') + def third = new Dependency(id: 'third', groupId: 'org.foo', artifactId: 'third', + versionRange: '1.1.8.RELEASE') + def metadata = InitializrMetadataTestBuilder.withDefaults() + .addDependencyGroup('test', first, second, third).build() + def dependencyMetadata = provider.get(metadata, Version.parse('1.1.5.RELEASE')) + assertEquals 2, dependencyMetadata.dependencies.size() + assertEquals 0, dependencyMetadata.repositories.size() + assertEquals 0, dependencyMetadata.boms.size() + assertSame first, dependencyMetadata.dependencies['first'] + assertSame second, dependencyMetadata.dependencies['second'] + } + + @Test + void resolveDependencies() { + def first = new Dependency(id: 'first', groupId: 'org.foo', artifactId: 'first') + first.versions << new Dependency.Mapping(versionRange: '[1.0.0.RELEASE, 1.1.0.RELEASE)', + version: '0.1.0.RELEASE') + first.versions << new Dependency.Mapping(versionRange: '1.1.0.RELEASE', + version: '0.2.0.RELEASE') + def second = new Dependency(id: 'second', groupId: 'org.foo', artifactId: 'second') + def metadata = InitializrMetadataTestBuilder.withDefaults() + .addDependencyGroup('test', first, second).build() + + def dependencyMetadata = provider.get(metadata, Version.parse('1.0.5.RELEASE')) + assertEquals 2, dependencyMetadata.dependencies.size() + assertEquals('0.1.0.RELEASE', dependencyMetadata.dependencies['first'].version) + + def anotherDependencyMetadata = provider.get(metadata, Version.parse('1.1.0.RELEASE')) + assertEquals 2, anotherDependencyMetadata.dependencies.size() + assertEquals('0.2.0.RELEASE', anotherDependencyMetadata.dependencies['first'].version) + } + + @Test + void addRepoAndRemoveDuplicates() { + def first = new Dependency(id: 'first', groupId: 'org.foo', artifactId: 'first', + repository: 'repo-foo') + def second = new Dependency(id: 'second', groupId: 'org.foo', artifactId: 'second') + def third = new Dependency(id: 'third', groupId: 'org.foo', artifactId: 'third', + repository: 'repo-foo') + def metadata = InitializrMetadataTestBuilder.withDefaults() + .addRepository('repo-foo', 'my-repo', 'http://localhost', false) + .addDependencyGroup('test', first, second, third).build() + def dependencyMetadata = provider.get(metadata, Version.parse('1.1.5.RELEASE')) + assertEquals 3, dependencyMetadata.dependencies.size() + assertEquals 1, dependencyMetadata.repositories.size() + assertEquals 0, dependencyMetadata.boms.size() + assertSame metadata.configuration.env.repositories.get('repo-foo'), + dependencyMetadata.repositories['repo-foo'] + } + + @Test + void addBomAndRemoveDuplicates() { + def first = new Dependency(id: 'first', groupId: 'org.foo', artifactId: 'first', + bom: 'bom-foo') + def second = new Dependency(id: 'second', groupId: 'org.foo', artifactId: 'second') + def third = new Dependency(id: 'third', groupId: 'org.foo', artifactId: 'third', + bom: 'bom-foo') + + def bom = new BillOfMaterials(groupId: 'org.foo', artifactId: 'bom') + bom.mappings << new BillOfMaterials.Mapping(versionRange: '[1.0.0.RELEASE, 1.1.8.RELEASE)', + version: '1.0.0.RELEASE') + bom.mappings << new BillOfMaterials.Mapping(versionRange: '1.1.8.RELEASE', + version: '2.0.0.RELEASE') + def metadata = InitializrMetadataTestBuilder.withDefaults() + .addBom('bom-foo',bom) + .addDependencyGroup('test', first, second, third).build() + def dependencyMetadata = provider.get(metadata, Version.parse('1.1.5.RELEASE')) + assertEquals 3, dependencyMetadata.dependencies.size() + assertEquals 0, dependencyMetadata.repositories.size() + assertEquals 1, dependencyMetadata.boms.size() + assertEquals 'org.foo', dependencyMetadata.boms['bom-foo'].groupId + assertEquals 'bom', dependencyMetadata.boms['bom-foo'].artifactId + assertEquals '1.0.0.RELEASE', dependencyMetadata.boms['bom-foo'].version + } + + @Test + void repoFromBomAccordingToVersion() { + def dependencyMetadata = testRepoFromBomAccordingToVersion('1.0.9.RELEASE') + assertEquals(Version.parse('1.0.9.RELEASE'), dependencyMetadata.bootVersion) + assertEquals 3, dependencyMetadata.dependencies.size() + assertEquals 2, dependencyMetadata.repositories.size() + assertEquals 1, dependencyMetadata.boms.size() + assertEquals 'foo', dependencyMetadata.repositories['repo-foo'].name + assertEquals 'bar', dependencyMetadata.repositories['repo-bar'].name + assertEquals 'org.foo', dependencyMetadata.boms['bom-foo'].groupId + assertEquals 'bom', dependencyMetadata.boms['bom-foo'].artifactId + assertEquals '2.0.0.RELEASE', dependencyMetadata.boms['bom-foo'].version + } + + @Test + void repoFromBomAccordingToAnotherVersion() { + def dependencyMetadata = testRepoFromBomAccordingToVersion('1.1.5.RELEASE') + assertEquals(Version.parse('1.1.5.RELEASE'), dependencyMetadata.bootVersion) + assertEquals 3, dependencyMetadata.dependencies.size() + assertEquals 2, dependencyMetadata.repositories.size() + assertEquals 1, dependencyMetadata.boms.size() + assertEquals 'foo', dependencyMetadata.repositories['repo-foo'].name + assertEquals 'biz', dependencyMetadata.repositories['repo-biz'].name + assertEquals 'org.foo', dependencyMetadata.boms['bom-foo'].groupId + assertEquals 'bom', dependencyMetadata.boms['bom-foo'].artifactId + assertEquals '3.0.0.RELEASE', dependencyMetadata.boms['bom-foo'].version + } + + private DependencyMetadata testRepoFromBomAccordingToVersion(bootVersion) { + def first = new Dependency(id: 'first', groupId: 'org.foo', artifactId: 'first', + repository: 'repo-foo') + def second = new Dependency(id: 'second', groupId: 'org.foo', artifactId: 'second') + def third = new Dependency(id: 'third', groupId: 'org.foo', artifactId: 'third', + bom: 'bom-foo') + + BillOfMaterials bom = new BillOfMaterials(groupId: 'org.foo', artifactId: 'bom') + bom.mappings << new BillOfMaterials.Mapping(versionRange: '[1.0.0.RELEASE, 1.1.0.RELEASE)', + version: '2.0.0.RELEASE', repositories: ['repo-foo', 'repo-bar']) + bom.mappings << new BillOfMaterials.Mapping(versionRange: '1.1.0.RELEASE', + version: '3.0.0.RELEASE', repositories: ['repo-biz']) + def metadata = InitializrMetadataTestBuilder.withDefaults() + .addBom('bom-foo', bom) + .addRepository('repo-foo', 'foo', 'http://localhost', false) + .addRepository('repo-bar', 'bar', 'http://localhost', false) + .addRepository('repo-biz', 'biz', 'http://localhost', false) + .addDependencyGroup('test', first, second, third).build() + provider.get(metadata, Version.parse(bootVersion)) + } + +} diff --git a/initializr/src/test/groovy/io/spring/initializr/web/MainControllerDependenciesTests.groovy b/initializr/src/test/groovy/io/spring/initializr/web/MainControllerDependenciesTests.groovy new file mode 100644 index 00000000..6308370c --- /dev/null +++ b/initializr/src/test/groovy/io/spring/initializr/web/MainControllerDependenciesTests.groovy @@ -0,0 +1,60 @@ +/* + * 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.web + +import org.json.JSONObject +import org.junit.Test +import org.skyscreamer.jsonassert.JSONAssert +import org.skyscreamer.jsonassert.JSONCompareMode + +import org.springframework.http.HttpHeaders +import org.springframework.http.ResponseEntity +import org.springframework.test.context.ActiveProfiles + +import static org.hamcrest.CoreMatchers.nullValue +import static org.hamcrest.core.IsNot.not +import static org.junit.Assert.assertThat + +/** + * @author Stephane Nicoll + */ +@ActiveProfiles('test-default') +class MainControllerDependenciesTests extends AbstractInitializrControllerIntegrationTests { + + @Test + void noBootVersion() { + ResponseEntity response = execute('/dependencies', String, null, 'application/json') + assertThat(response.getHeaders().getFirst(HttpHeaders.ETAG), not(nullValue())) + validateContentType(response, CURRENT_METADATA_MEDIA_TYPE) + validateDependenciesOutput('1.1.4', new JSONObject(response.body)) + } + + @Test + void filteredDependencies() { + ResponseEntity response = execute('/dependencies?bootVersion=1.2.1.RELEASE', + String, null, 'application/json') + assertThat(response.getHeaders().getFirst(HttpHeaders.ETAG), not(nullValue())) + validateContentType(response, CURRENT_METADATA_MEDIA_TYPE) + validateDependenciesOutput('1.2.1', new JSONObject(response.body)) + } + + protected void validateDependenciesOutput(String version, JSONObject actual) { + def expected = readJsonFrom("metadata/dependencies/test-dependencies-$version" + ".json") + JSONAssert.assertEquals(expected, actual, JSONCompareMode.STRICT) + } + +} diff --git a/initializr/src/test/groovy/io/spring/initializr/web/UiControllerIntegrationTests.groovy b/initializr/src/test/groovy/io/spring/initializr/web/UiControllerIntegrationTests.groovy index 312b30f5..2f078e85 100644 --- a/initializr/src/test/groovy/io/spring/initializr/web/UiControllerIntegrationTests.groovy +++ b/initializr/src/test/groovy/io/spring/initializr/web/UiControllerIntegrationTests.groovy @@ -46,7 +46,7 @@ class UiControllerIntegrationTests extends AbstractInitializrControllerIntegrati } protected void validateDependenciesOutput(String version, JSONObject actual) { - def expected = readJsonFrom("metadata/dependencies/test-dependencies-$version" + ".json") + def expected = readJsonFrom("metadata/ui/test-dependencies-$version" + ".json") JSONAssert.assertEquals(expected, actual, JSONCompareMode.STRICT) } diff --git a/initializr/src/test/resources/application-test-default.yml b/initializr/src/test/resources/application-test-default.yml index bfca8d7e..ffde9383 100644 --- a/initializr/src/test/resources/application-test-default.yml +++ b/initializr/src/test/resources/application-test-default.yml @@ -3,6 +3,25 @@ info: version: 1.1.4.RELEASE initializr: + env: + boms: + my-api-bom: + groupId: org.acme + artifactId: my-api-bom + mappings: + - versionRange: "[1.0.0.RELEASE,1.1.6.RELEASE)" + version: 1.0.0.RELEASE + repositories: my-api-repo-1 + - versionRange: "1.2.1.RELEASE" + version: 2.0.0.RELEASE + repositories: my-api-repo-2 + repositories: + my-api-repo-1: + name: repo1 + url: http://example.com/repo1 + my-api-repo-2: + name: repo2 + url: http://example.com/repo2 dependencies: - name: Core content: @@ -46,6 +65,7 @@ initializr: groupId: org.acme artifactId: my-api scope: provided + bom: my-api-bom types: - name: Maven POM id: maven-build diff --git a/initializr/src/test/resources/metadata/config/test-default.json b/initializr/src/test/resources/metadata/config/test-default.json index 2455670b..f3d694b2 100644 --- a/initializr/src/test/resources/metadata/config/test-default.json +++ b/initializr/src/test/resources/metadata/config/test-default.json @@ -31,7 +31,6 @@ }, "configuration": {"env": { "artifactRepository": "https://repo.spring.io/release/", - "boms": {}, "fallbackApplicationName": "Application", "forceSsl": true, "invalidApplicationNames": [ @@ -39,6 +38,16 @@ "SpringBootApplication" ], "repositories": { + "my-api-repo-1": { + "name": "repo1", + "url": "http://example.com/repo1", + "snapshotsEnabled": false + }, + "my-api-repo-2": { + "name": "repo2", + "url": "http://example.com/repo2", + "snapshotsEnabled": false + }, "spring-milestones": { "name": "Spring Milestones", "snapshotsEnabled": false, @@ -50,6 +59,29 @@ "url": "https://repo.spring.io/snapshot" } }, + "boms": { + "my-api-bom": { + "groupId": "org.acme", + "artifactId": "my-api-bom", + "repositories": [], + "mappings": [ + { + "versionRange": "[1.0.0.RELEASE,1.1.6.RELEASE)", + "repositories": [ + "my-api-repo-1" + ], + "version": "1.0.0.RELEASE" + }, + { + "versionRange": "1.2.1.RELEASE", + "repositories": [ + "my-api-repo-2" + ], + "version": "2.0.0.RELEASE" + } + ] + } + }, "springBootMetadataUrl": "https://spring.io/project_metadata/spring-boot" }}, "dependencies": { @@ -134,7 +166,8 @@ "groupId": "org.acme", "id": "my-api", "name": "My API", - "scope": "provided" + "scope": "provided", + "bom": "my-api-bom" } ], "name": "Other" diff --git a/initializr/src/test/resources/metadata/dependencies/test-dependencies-1.1.4.json b/initializr/src/test/resources/metadata/dependencies/test-dependencies-1.1.4.json new file mode 100644 index 00000000..53880feb --- /dev/null +++ b/initializr/src/test/resources/metadata/dependencies/test-dependencies-1.1.4.json @@ -0,0 +1,61 @@ +{ + "bootVersion": "1.1.4.RELEASE", + "repositories": { + "my-api-repo-1": { + "name": "repo1", + "url": "http://example.com/repo1", + "snapshotEnabled": false + } + }, + "boms": { + "my-api-bom": { + "groupId": "org.acme", + "artifactId": "my-api-bom", + "version": "1.0.0.RELEASE", + "repositories": [ + "my-api-repo-1" + ] + } + }, + "dependencies": { + "web": { + "groupId": "org.springframework.boot", + "scope": "compile", + "artifactId": "spring-boot-starter-web" + }, + "security": { + "groupId": "org.springframework.boot", + "scope": "compile", + "artifactId": "spring-boot-starter-security" + }, + "data-jpa": { + "groupId": "org.springframework.boot", + "scope": "compile", + "artifactId": "spring-boot-starter-data-jpa" + }, + "org.acme:foo": { + "groupId": "org.acme", + "scope": "compile", + "artifactId": "foo", + "version": "1.3.5" + }, + "org.acme:bar": { + "groupId": "org.acme", + "scope": "compile", + "artifactId": "bar", + "version": "2.1.0" + }, + "org.acme:bur": { + "groupId": "org.acme", + "scope": "test", + "artifactId": "bur", + "version": "2.1.0" + }, + "my-api": { + "groupId": "org.acme", + "scope": "provided", + "artifactId": "my-api", + "bom": "my-api-bom" + } + } +} \ No newline at end of file diff --git a/initializr/src/test/resources/metadata/dependencies/test-dependencies-1.2.1.json b/initializr/src/test/resources/metadata/dependencies/test-dependencies-1.2.1.json new file mode 100644 index 00000000..a32f02a0 --- /dev/null +++ b/initializr/src/test/resources/metadata/dependencies/test-dependencies-1.2.1.json @@ -0,0 +1,61 @@ +{ + "bootVersion": "1.2.1.RELEASE", + "repositories": { + "my-api-repo-2": { + "name": "repo2", + "url": "http://example.com/repo2", + "snapshotEnabled": false + } + }, + "boms": { + "my-api-bom": { + "groupId": "org.acme", + "artifactId": "my-api-bom", + "version": "2.0.0.RELEASE", + "repositories": [ + "my-api-repo-2" + ] + } + }, + "dependencies": { + "web": { + "groupId": "org.springframework.boot", + "scope": "compile", + "artifactId": "spring-boot-starter-web" + }, + "security": { + "groupId": "org.springframework.boot", + "scope": "compile", + "artifactId": "spring-boot-starter-security" + }, + "data-jpa": { + "groupId": "org.springframework.boot", + "scope": "compile", + "artifactId": "spring-boot-starter-data-jpa" + }, + "org.acme:foo": { + "groupId": "org.acme", + "scope": "compile", + "artifactId": "foo", + "version": "1.3.5" + }, + "org.acme:bar": { + "groupId": "org.acme", + "scope": "compile", + "artifactId": "bar", + "version": "2.1.0" + }, + "org.acme:biz": { + "groupId": "org.acme", + "scope": "runtime", + "artifactId": "biz", + "version": "1.3.5" + }, + "my-api": { + "groupId": "org.acme", + "scope": "provided", + "artifactId": "my-api", + "bom": "my-api-bom" + } + } +} \ No newline at end of file diff --git a/initializr/src/test/resources/metadata/test-default-2.1.0.json b/initializr/src/test/resources/metadata/test-default-2.1.0.json index 34f1469c..c06f4e0a 100644 --- a/initializr/src/test/resources/metadata/test-default-2.1.0.json +++ b/initializr/src/test/resources/metadata/test-default-2.1.0.json @@ -1,5 +1,9 @@ { "_links": { + "dependencies": { + "href": "https://localhost:@port@/dependencies{?bootVersion}", + "templated": true + }, "maven-build": { "href": "https://localhost:@port@/pom.xml?type=maven-build{&dependencies,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}", "templated": true diff --git a/initializr/src/test/resources/metadata/dependencies/test-dependencies-1.1.2.json b/initializr/src/test/resources/metadata/ui/test-dependencies-1.1.2.json similarity index 100% rename from initializr/src/test/resources/metadata/dependencies/test-dependencies-1.1.2.json rename to initializr/src/test/resources/metadata/ui/test-dependencies-1.1.2.json diff --git a/initializr/src/test/resources/metadata/dependencies/test-dependencies-all.json b/initializr/src/test/resources/metadata/ui/test-dependencies-all.json similarity index 100% rename from initializr/src/test/resources/metadata/dependencies/test-dependencies-all.json rename to initializr/src/test/resources/metadata/ui/test-dependencies-all.json