From 95441ef19cf84271ca56c4fe9c7dd03af22c40ff Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 19 Aug 2014 16:25:42 +0200 Subject: [PATCH] Redirect Spring cli distribution bundle This commit adds the '/spring' endpoint that is used to download the Spring CLI distribution bundle. Instead of relying on the presence of a local 'spring.zip' file uploaded as part of the application, a redirect to a configurable repository is used. It is possible to download both the zip and the tar.gz distribution by specifying the extension in the url (i.e. /spring.tar.gz provides the tar.gz distribution. Fixes gh-31 --- README.md | 10 ++-- .../initializr/InitializrMetadata.groovy | 53 ++++++++++++++++--- .../initializr/web/MainController.groovy | 12 +++++ .../initializr/InitializrMetadataTests.groovy | 30 ++++++++--- .../initializr/ProjectGeneratorTests.groovy | 6 +-- .../initializr/ProjectRequestTests.groovy | 8 +-- .../support/InitializrMetadataBuilder.groovy | 6 ++- .../MainControllerEnvIntegrationTests.groovy | 41 ++++++++++++++ .../web/MainControllerIntegrationTests.groovy | 28 ++++++++++ .../resources/application-test-custom-env.yml | 3 ++ .../resources/metadata/test-default-1.0.json | 7 ++- 11 files changed, 174 insertions(+), 30 deletions(-) create mode 100644 initializr/src/test/groovy/io/spring/initializr/web/MainControllerEnvIntegrationTests.groovy create mode 100644 initializr/src/test/resources/application-test-custom-env.yml diff --git a/README.md b/README.md index 9a415a88..4495dbd2 100644 --- a/README.md +++ b/README.md @@ -71,14 +71,12 @@ An example Cloud Foundry `manifest.yml` file is provided. You should ensure that the application name and URL (name and host values) are suitable for your environment before running `cf push`. -You can jar up the app and make it executable in any environment. Care is needed with the includes and excludes: +You can jar up the app and make it executable in any environment. + + $ spring jar start.jar app.groovy - $ version=1.1.5.RELEASE - $ wget -O spring.zip https://repo.spring.io/org/springframework/boot/spring-boot-cli/${version}/spring-boot-cli-${version}-bin.zip - $ spring jar --include '+spring.zip' start.jar app.groovy - To deploy on Cloudfoundry: - + $ cf push start -p start.jar -n start- Where `` is the name of the space. As a failsafe, and a diff --git a/initializr/src/main/groovy/io/spring/initializr/InitializrMetadata.groovy b/initializr/src/main/groovy/io/spring/initializr/InitializrMetadata.groovy index 8d812eb9..4f000d22 100644 --- a/initializr/src/main/groovy/io/spring/initializr/InitializrMetadata.groovy +++ b/initializr/src/main/groovy/io/spring/initializr/InitializrMetadata.groovy @@ -21,6 +21,8 @@ import javax.annotation.PostConstruct import com.fasterxml.jackson.annotation.JsonIgnore import com.fasterxml.jackson.annotation.JsonInclude import groovy.transform.ToString +import org.slf4j.Logger +import org.slf4j.LoggerFactory import org.springframework.boot.context.properties.ConfigurationProperties @@ -33,6 +35,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties *
  • Supported Java versions
  • *
  • Supported language
  • *
  • Supported Spring Boot versions
  • + *
  • Default settings used to generate the project
  • + *
  • Environment related settings
  • * * * @author Stephane Nicoll @@ -41,6 +45,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties @ConfigurationProperties(prefix = 'initializr', ignoreUnknownFields = false) class InitializrMetadata { + private static final Logger logger = LoggerFactory.getLogger(InitializrMetadata) + final List dependencies = new ArrayList() final List types = new ArrayList() @@ -55,6 +61,9 @@ class InitializrMetadata { final Defaults defaults = new Defaults() + @JsonIgnore + final Env env = new Env() + @JsonIgnore final Map indexedDependencies = new HashMap() @@ -76,11 +85,6 @@ class InitializrMetadata { request[key] = value } } - request.type = getDefault(types, request.type) - request.packaging = getDefault(packagings, request.packaging) - request.javaVersion = getDefault(javaVersions, request.javaVersion) - request.language = getDefault(languages, request.language) - request.bootVersion = getDefault(bootVersions, request.bootVersion) request } @@ -98,6 +102,13 @@ class InitializrMetadata { } } } + env.validate() + + defaults.type = getDefault(types) + defaults.packaging = getDefault(packagings) + defaults.javaVersion = getDefault(javaVersions) + defaults.language = getDefault(languages) + defaults.bootVersion = getDefault(bootVersions) } private void indexDependency(String id, Dependency dependency) { @@ -135,13 +146,14 @@ class InitializrMetadata { } } - static def getDefault(List elements, String defaultValue) { + static def getDefault(List elements) { for (DefaultIdentifiableElement element : elements) { if (element.default) { return element.id } } - return defaultValue + logger.warn('No default found amongst' + elements) + return (elements.isEmpty() ? null : elements.get(0).id) } @JsonInclude(JsonInclude.Include.NON_NULL) @@ -225,6 +237,11 @@ class InitializrMetadata { String name = 'demo' String description = 'Demo project for Spring Boot' String packageName + String type + String packaging + String javaVersion + String language + String bootVersion /** * Return the artifactId or the name of the project if none is set. @@ -242,6 +259,28 @@ class InitializrMetadata { } + /** + * Defines additional environment settings + */ + static class Env { + + String artifactRepository = 'https://repo.spring.io/release/' + + /** + * Create an URL suitable to download Spring Boot cli for the specified version and extension. + */ + String createCliDistributionURl(String version, String extension) { + artifactRepository + "org/springframework/boot/spring-boot-cli/$version/spring-boot-cli-$version-bin.$extension" + } + + void validate() { + if (!artifactRepository.endsWith('/')) { + artifactRepository = artifactRepository + '/' + } + } + + } + static class DefaultIdentifiableElement extends IdentifiableElement { @JsonIgnore 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 9d0a58d5..af518219 100644 --- a/initializr/src/main/groovy/io/spring/initializr/web/MainController.groovy +++ b/initializr/src/main/groovy/io/spring/initializr/web/MainController.groovy @@ -74,6 +74,16 @@ class MainController { template 'home.html', model } + @RequestMapping('/spring') + String spring() { + 'redirect:' + metadata.env.createCliDistributionURl(metadata.defaults.bootVersion, 'zip') + } + + @RequestMapping(value = ['/spring.tar.gz', 'spring.tgz']) + String springTgz() { + 'redirect:' + metadata.env.createCliDistributionURl(metadata.defaults.bootVersion, 'tar.gz') + } + @RequestMapping('/pom') @ResponseBody ResponseEntity pom(ProjectRequest request) { @@ -124,4 +134,6 @@ class MainController { result } + + } diff --git a/initializr/src/test/groovy/io/spring/initializr/InitializrMetadataTests.groovy b/initializr/src/test/groovy/io/spring/initializr/InitializrMetadataTests.groovy index f6a01357..9c14a867 100644 --- a/initializr/src/test/groovy/io/spring/initializr/InitializrMetadataTests.groovy +++ b/initializr/src/test/groovy/io/spring/initializr/InitializrMetadataTests.groovy @@ -120,7 +120,7 @@ class InitializrMetadataTests { InitializrMetadata metadata = InitializrMetadataBuilder.withDefaults() - .addDependencyGroup('foo', dependency, dependency2).get() + .addDependencyGroup('foo', dependency, dependency2).validateAndGet() assertSame dependency, metadata.getDependency('first') assertSame dependency2, metadata.getDependency('second') @@ -137,7 +137,7 @@ class InitializrMetadataTests { thrown.expect(IllegalArgumentException) thrown.expectMessage('conflict') - builder.get() + builder.validateAndGet() } @Test @@ -147,7 +147,7 @@ class InitializrMetadataTests { dependency.aliases.add('alias2') InitializrMetadata metadata = InitializrMetadataBuilder.withDefaults() - .addDependencyGroup('foo', dependency).get() + .addDependencyGroup('foo', dependency).validateAndGet() assertSame dependency, metadata.getDependency('first') assertSame dependency, metadata.getDependency('alias1') @@ -168,28 +168,42 @@ class InitializrMetadataTests { thrown.expect(IllegalArgumentException) thrown.expectMessage('alias2') - builder.get() + builder.validateAndGet() } @Test void createProjectRequest() { - InitializrMetadata metadata = InitializrMetadataBuilder.withDefaults().get() + InitializrMetadata metadata = InitializrMetadataBuilder.withDefaults().validateAndGet() ProjectRequest request = doCreateProjectRequest(metadata) assertEquals metadata.defaults.groupId, request.groupId } + @Test + void validateArtifactRepository() { + InitializrMetadata metadata = InitializrMetadataBuilder.withDefaults().instance() + metadata.env.artifactRepository = 'http://foo/bar' + metadata.validate() + assertEquals 'http://foo/bar/', metadata.env.artifactRepository + } + @Test void getDefaultNoDefault() { List elements = [] elements << createJavaVersion('one', false) << createJavaVersion('two', false) - assertEquals 'three', InitializrMetadata.getDefault(elements, 'three') + assertEquals 'one', InitializrMetadata.getDefault(elements) } @Test - void getDefaultWithDefault() { + void getDefaultEmpty() { + List elements = [] + assertNull InitializrMetadata.getDefault(elements) + } + + @Test + void getDefault() { List elements = [] elements << createJavaVersion('one', false) << createJavaVersion('two', true) - assertEquals 'two', InitializrMetadata.getDefault(elements, 'three') + assertEquals 'two', InitializrMetadata.getDefault(elements) } private static ProjectRequest doCreateProjectRequest(InitializrMetadata metadata) { diff --git a/initializr/src/test/groovy/io/spring/initializr/ProjectGeneratorTests.groovy b/initializr/src/test/groovy/io/spring/initializr/ProjectGeneratorTests.groovy index f44926b4..8b81c035 100644 --- a/initializr/src/test/groovy/io/spring/initializr/ProjectGeneratorTests.groovy +++ b/initializr/src/test/groovy/io/spring/initializr/ProjectGeneratorTests.groovy @@ -31,7 +31,7 @@ class ProjectGeneratorTests { @Before void setup() { InitializrMetadata metadata = InitializrMetadataBuilder.withDefaults() - .addDependencyGroup('test', 'web', 'security', 'data-jpa', 'aop', 'batch', 'integration').get() + .addDependencyGroup('test', 'web', 'security', 'data-jpa', 'aop', 'batch', 'integration').validateAndGet() projectGenerator.metadata = metadata } @@ -59,7 +59,7 @@ class ProjectGeneratorTests { dependency.facets << 'web' InitializrMetadata metadata = InitializrMetadataBuilder.withDefaults() .addDependencyGroup('core', 'web', 'security', 'data-jpa') - .addDependencyGroup('test', dependency).get() + .addDependencyGroup('test', dependency).validateAndGet() projectGenerator.metadata = metadata ProjectRequest request = createProjectRequest('thymeleaf') @@ -78,7 +78,7 @@ class ProjectGeneratorTests { dependency.facets << 'web' InitializrMetadata metadata = InitializrMetadataBuilder.withDefaults() .addDependencyGroup('core', 'web', 'security', 'data-jpa') - .addDependencyGroup('test', dependency).get() + .addDependencyGroup('test', dependency).validateAndGet() projectGenerator.metadata = metadata ProjectRequest request = createProjectRequest('thymeleaf') diff --git a/initializr/src/test/groovy/io/spring/initializr/ProjectRequestTests.groovy b/initializr/src/test/groovy/io/spring/initializr/ProjectRequestTests.groovy index 276a8826..12231e1f 100644 --- a/initializr/src/test/groovy/io/spring/initializr/ProjectRequestTests.groovy +++ b/initializr/src/test/groovy/io/spring/initializr/ProjectRequestTests.groovy @@ -35,7 +35,7 @@ class ProjectRequestTests { void resolve() { ProjectRequest request = new ProjectRequest() InitializrMetadata metadata = InitializrMetadataBuilder.withDefaults() - .addDependencyGroup('code', 'web', 'security', 'spring-data').get() + .addDependencyGroup('code', 'web', 'security', 'spring-data').validateAndGet() request.style << 'web' << 'spring-data' request.resolve(metadata) @@ -47,7 +47,7 @@ class ProjectRequestTests { void resolveFullMetadata() { ProjectRequest request = new ProjectRequest() InitializrMetadata metadata = InitializrMetadataBuilder.withDefaults() - .addDependencyGroup('code', createDependency('org.foo', 'acme', '1.2.0')).get() + .addDependencyGroup('code', createDependency('org.foo', 'acme', '1.2.0')).validateAndGet() request.style << 'org.foo:acme' request.resolve(metadata) assertDependency(request.dependencies.get(0), 'org.foo', 'acme', '1.2.0') @@ -57,7 +57,7 @@ class ProjectRequestTests { void resolveUnknownSimpleIdAsSpringBootStarter() { ProjectRequest request = new ProjectRequest() InitializrMetadata metadata = InitializrMetadataBuilder.withDefaults() - .addDependencyGroup('code', 'org.foo:bar').get() + .addDependencyGroup('code', 'org.foo:bar').validateAndGet() request.style << 'org.foo:bar' << 'foo-bar' request.resolve(metadata) @@ -69,7 +69,7 @@ class ProjectRequestTests { void resolveUnknownDependency() { ProjectRequest request = new ProjectRequest() InitializrMetadata metadata = InitializrMetadataBuilder.withDefaults() - .addDependencyGroup('code', 'org.foo:bar').get() + .addDependencyGroup('code', 'org.foo:bar').validateAndGet() request.style << 'org.foo:acme' // does not exist and diff --git a/initializr/src/test/groovy/io/spring/initializr/support/InitializrMetadataBuilder.groovy b/initializr/src/test/groovy/io/spring/initializr/support/InitializrMetadataBuilder.groovy index 0a0b411d..109e6747 100644 --- a/initializr/src/test/groovy/io/spring/initializr/support/InitializrMetadataBuilder.groovy +++ b/initializr/src/test/groovy/io/spring/initializr/support/InitializrMetadataBuilder.groovy @@ -33,8 +33,12 @@ class InitializrMetadataBuilder { new InitializrMetadataBuilder().addDefaults() } - InitializrMetadata get() { + InitializrMetadata validateAndGet() { metadata.validate() + instance() + } + + InitializrMetadata instance() { metadata } diff --git a/initializr/src/test/groovy/io/spring/initializr/web/MainControllerEnvIntegrationTests.groovy b/initializr/src/test/groovy/io/spring/initializr/web/MainControllerEnvIntegrationTests.groovy new file mode 100644 index 00000000..32b0b0db --- /dev/null +++ b/initializr/src/test/groovy/io/spring/initializr/web/MainControllerEnvIntegrationTests.groovy @@ -0,0 +1,41 @@ +/* + * Copyright 2012-2014 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.junit.Test + +import org.springframework.http.HttpEntity +import org.springframework.http.HttpStatus +import org.springframework.test.context.ActiveProfiles + +import static org.junit.Assert.assertEquals + +/** + * @author Stephane Nicoll + */ +@ActiveProfiles(['test-default', 'test-custom-env']) +class MainControllerEnvIntegrationTests extends AbstractMainControllerIntegrationTests { + + @Test + void downloadCliWithCustomRepository() { + HttpEntity entity = restTemplate.getForEntity(createUrl('/spring'), HttpEntity.class) + assertEquals HttpStatus.FOUND, entity.getStatusCode() + assertEquals new URI('https://repo.spring.io/lib-release/org/springframework/boot/spring-boot-cli/1.1.5.RELEASE' + + '/spring-boot-cli-1.1.5.RELEASE-bin.zip'), entity.getHeaders().getLocation() + } + +} diff --git a/initializr/src/test/groovy/io/spring/initializr/web/MainControllerIntegrationTests.groovy b/initializr/src/test/groovy/io/spring/initializr/web/MainControllerIntegrationTests.groovy index b2607862..de1bc56a 100644 --- a/initializr/src/test/groovy/io/spring/initializr/web/MainControllerIntegrationTests.groovy +++ b/initializr/src/test/groovy/io/spring/initializr/web/MainControllerIntegrationTests.groovy @@ -62,6 +62,34 @@ class MainControllerIntegrationTests extends AbstractMainControllerIntegrationTe .isGradleProject() } + @Test + void downloadCli() { + assertSpringCliRedirect('/spring', 'zip') + } + + @Test + void downloadCliAsZip() { + assertSpringCliRedirect('/spring.zip', 'zip') + } + + @Test + void downloadCliAsTarGz() { + assertSpringCliRedirect('/spring.tar.gz', 'tar.gz') + } + + @Test + void downloadCliAsTgz() { + assertSpringCliRedirect('/spring.tgz', 'tar.gz') + } + + private void assertSpringCliRedirect(String context, String extension) { + ResponseEntity entity = restTemplate.getForEntity(createUrl(context), ResponseEntity.class) + assertEquals HttpStatus.FOUND, entity.getStatusCode() + assertEquals new URI('https://repo.spring.io/release/org/springframework/boot/spring-boot-cli/1.1.5.RELEASE' + + '/spring-boot-cli-1.1.5.RELEASE-bin.'+extension), entity.getHeaders().getLocation() + + } + @Test // Test that the current output is exactly what we expect void validateCurrentProjectMetadata() { String json = restTemplate.getForObject(createUrl('/'), String.class) diff --git a/initializr/src/test/resources/application-test-custom-env.yml b/initializr/src/test/resources/application-test-custom-env.yml new file mode 100644 index 00000000..34422237 --- /dev/null +++ b/initializr/src/test/resources/application-test-custom-env.yml @@ -0,0 +1,3 @@ +initializr: + env: + artifactRepository: https://repo.spring.io/lib-release \ No newline at end of file diff --git a/initializr/src/test/resources/metadata/test-default-1.0.json b/initializr/src/test/resources/metadata/test-default-1.0.json index 95ffdb86..f4f39703 100644 --- a/initializr/src/test/resources/metadata/test-default-1.0.json +++ b/initializr/src/test/resources/metadata/test-default-1.0.json @@ -114,6 +114,11 @@ "version": "0.0.1-SNAPSHOT", "name": "demo", "description": "Demo project for Spring Boot", - "packageName": "demo" + "packageName": "demo", + "type": "starter.zip", + "packaging": "jar", + "javaVersion": "1.7", + "language": "java", + "bootVersion": "1.1.5.RELEASE" } } \ No newline at end of file