Always set a default boot version

Previously, if the sagan meta-data did not provide a default, the live
instance wouldn't have one either. This means that all requests that
do not provide an explicit boot version will fail as well.

This commit sets the first version as the default if no default exists.

Closes gh-267
This commit is contained in:
Stephane Nicoll
2016-07-29 12:30:50 +02:00
parent edd590ef13
commit d018782726
8 changed files with 256 additions and 32 deletions

View File

@@ -0,0 +1,80 @@
{
"id": "spring-boot",
"name": "Spring Boot",
"repoUrl": "https://github.com/spring-projects/spring-boot",
"siteUrl": "http://projects.spring.io/spring-boot",
"category": "active",
"stackOverflowTags": "spring-boot",
"projectReleases": [
{
"releaseStatus": "SNAPSHOT",
"refDocUrl": "http://docs.spring.io/spring-boot/docs/1.3.1.BUILD-SNAPSHOT/reference/htmlsingle/",
"apiDocUrl": "http://docs.spring.io/spring-boot/docs/1.3.1.BUILD-SNAPSHOT/api/",
"groupId": "org.springframework.boot",
"artifactId": "spring-boot",
"repository": {
"id": "spring-snapshots",
"name": "Spring Snapshots",
"url": "https://repo.spring.io/libs-snapshot",
"snapshotsEnabled": true
},
"preRelease": false,
"generalAvailability": false,
"versionDisplayName": "1.3.1",
"current": false,
"snapshot": true,
"version": "1.3.1.BUILD-SNAPSHOT"
},
{
"releaseStatus": "GENERAL_AVAILABILITY",
"refDocUrl": "http://docs.spring.io/spring-boot/docs/1.3.0.RELEASE/reference/htmlsingle/",
"apiDocUrl": "http://docs.spring.io/spring-boot/docs/1.3.0.RELEASE/api/",
"groupId": "org.springframework.boot",
"artifactId": "spring-boot",
"repository": null,
"preRelease": false,
"generalAvailability": true,
"versionDisplayName": "1.3.0",
"current": false,
"snapshot": false,
"version": "1.3.0.RELEASE"
},
{
"releaseStatus": "SNAPSHOT",
"refDocUrl": "http://docs.spring.io/spring-boot/docs/1.2.6.BUILD-SNAPSHOT/reference/htmlsingle/",
"apiDocUrl": "http://docs.spring.io/spring-boot/docs/1.2.6.BUILD-SNAPSHOT/api/",
"groupId": "org.springframework.boot",
"artifactId": "spring-boot",
"repository": {
"id": "spring-snapshots",
"name": "Spring Snapshots",
"url": "https://repo.spring.io/libs-snapshot",
"snapshotsEnabled": true
},
"preRelease": false,
"generalAvailability": false,
"versionDisplayName": "1.2.6",
"current": false,
"snapshot": true,
"version": "1.2.6.BUILD-SNAPSHOT"
},
{
"releaseStatus": "GENERAL_AVAILABILITY",
"refDocUrl": "http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/",
"apiDocUrl": "http://docs.spring.io/spring-boot/docs/current/api/",
"groupId": "org.springframework.boot",
"artifactId": "spring-boot",
"repository": null,
"preRelease": false,
"generalAvailability": true,
"versionDisplayName": "1.2.5",
"current": false,
"snapshot": false,
"version": "1.2.5.RELEASE"
}
],
"aggregator": false,
"stackOverflowTagList": [
"spring-boot"
]
}

View File

@@ -0,0 +1,80 @@
{
"id": "spring-boot",
"name": "Spring Boot",
"repoUrl": "https://github.com/spring-projects/spring-boot",
"siteUrl": "http://projects.spring.io/spring-boot",
"category": "active",
"stackOverflowTags": "spring-boot",
"projectReleases": [
{
"releaseStatus": "SNAPSHOT",
"refDocUrl": "http://docs.spring.io/spring-boot/docs/1.4.1.BUILD-SNAPSHOT/reference/htmlsingle/",
"apiDocUrl": "http://docs.spring.io/spring-boot/docs/1.4.1.BUILD-SNAPSHOT/api/",
"groupId": "org.springframework.boot",
"artifactId": "spring-boot",
"repository": {
"id": "spring-snapshots",
"name": "Spring Snapshots",
"url": "https://repo.spring.io/libs-snapshot",
"snapshotsEnabled": true
},
"preRelease": false,
"generalAvailability": false,
"versionDisplayName": "1.4.1",
"current": false,
"snapshot": true,
"version": "1.4.1.BUILD-SNAPSHOT"
},
{
"releaseStatus": "GENERAL_AVAILABILITY",
"refDocUrl": "http://docs.spring.io/spring-boot/docs/1.4.0.RELEASE/reference/htmlsingle/",
"apiDocUrl": "http://docs.spring.io/spring-boot/docs/1.4.0.RELEASE/api/",
"groupId": "org.springframework.boot",
"artifactId": "spring-boot",
"repository": null,
"preRelease": false,
"generalAvailability": true,
"versionDisplayName": "1.4.0",
"current": true,
"snapshot": false,
"version": "1.4.0.RELEASE"
},
{
"releaseStatus": "SNAPSHOT",
"refDocUrl": "http://docs.spring.io/spring-boot/docs/1.3.8.BUILD-SNAPSHOT/reference/htmlsingle/",
"apiDocUrl": "http://docs.spring.io/spring-boot/docs/1.3.8.BUILD-SNAPSHOT/api/",
"groupId": "org.springframework.boot",
"artifactId": "spring-boot",
"repository": {
"id": "spring-snapshots",
"name": "Spring Snapshots",
"url": "https://repo.spring.io/libs-snapshot",
"snapshotsEnabled": true
},
"preRelease": false,
"generalAvailability": false,
"versionDisplayName": "1.3.8",
"current": false,
"snapshot": true,
"version": "1.3.8.BUILD-SNAPSHOT"
},
{
"releaseStatus": "GENERAL_AVAILABILITY",
"refDocUrl": "http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/",
"apiDocUrl": "http://docs.spring.io/spring-boot/docs/current/api/",
"groupId": "org.springframework.boot",
"artifactId": "spring-boot",
"repository": null,
"preRelease": false,
"generalAvailability": true,
"versionDisplayName": "1.3.7",
"current": false,
"snapshot": false,
"version": "1.3.7.RELEASE"
}
],
"aggregator": false,
"stackOverflowTagList": [
"spring-boot"
]
}

View File

@@ -41,6 +41,7 @@ import org.springframework.cache.concurrent.ConcurrentMapCache
import org.springframework.cache.support.SimpleCacheManager
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.web.client.RestTemplate
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
@@ -100,7 +101,7 @@ class InitializrAutoConfiguration {
@ConditionalOnMissingBean(InitializrMetadataProvider)
InitializrMetadataProvider initializrMetadataProvider(InitializrProperties properties) {
def metadata = InitializrMetadataBuilder.fromInitializrProperties(properties).build()
new DefaultInitializrMetadataProvider(metadata)
new DefaultInitializrMetadataProvider(metadata, new RestTemplate())
}
@Bean

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2015 the original author or authors.
* Copyright 2012-2016 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.
@@ -21,8 +21,8 @@ import io.spring.initializr.metadata.DefaultMetadataElement
import io.spring.initializr.metadata.InitializrMetadata
import io.spring.initializr.metadata.InitializrMetadataProvider
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.cache.annotation.Cacheable
import org.springframework.web.client.RestTemplate
/**
* A default {@link InitializrMetadataProvider} that is able to refresh
@@ -35,21 +35,29 @@ import org.springframework.cache.annotation.Cacheable
class DefaultInitializrMetadataProvider implements InitializrMetadataProvider {
private final InitializrMetadata metadata
private final RestTemplate restTemplate
@Autowired
DefaultInitializrMetadataProvider(InitializrMetadata metadata) {
DefaultInitializrMetadataProvider(InitializrMetadata metadata, RestTemplate restTemplate) {
this.metadata = metadata
this.restTemplate = restTemplate
}
@Override
@Cacheable(value = 'initializr', key = "'metadata'")
InitializrMetadata get() {
updateInitializrMetadata(metadata)
metadata
}
protected void updateInitializrMetadata(InitializrMetadata metadata) {
def bootVersions = fetchBootVersions()
if (bootVersions) {
if (!bootVersions.find { it.default }) { // No default specified
bootVersions[0].default = true
}
metadata.bootVersions.content.clear()
metadata.bootVersions.content.addAll(bootVersions)
}
metadata
}
protected List<DefaultMetadataElement> fetchBootVersions() {
@@ -57,7 +65,7 @@ class DefaultInitializrMetadataProvider implements InitializrMetadataProvider {
if (url) {
try {
log.info("Fetching boot metadata from $url")
return new SpringBootMetadataReader(url).bootVersions
return new SpringBootMetadataReader(restTemplate, url).bootVersions
} catch (Exception e) {
log.warn('Failed to fetch spring boot metadata', e)
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2015 the original author or authors.
* Copyright 2012-2016 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.
@@ -36,8 +36,7 @@ class SpringBootMetadataReader {
/**
* Parse the content of the metadata at the specified url
*/
SpringBootMetadataReader(String url) {
def restTemplate = new RestTemplate()
SpringBootMetadataReader(RestTemplate restTemplate, String url) {
def content = restTemplate.getForObject(url, String.class)
this.content = new JsonSlurper().parseText(content)
}

View File

@@ -18,7 +18,7 @@ package io.spring.initializr.web
import java.nio.charset.Charset
import io.spring.initializr.metadata.DefaultMetadataElement
import io.spring.initializr.metadata.InitializrMetadata
import io.spring.initializr.metadata.InitializrMetadataBuilder
import io.spring.initializr.metadata.InitializrMetadataProvider
import io.spring.initializr.metadata.InitializrProperties
@@ -48,7 +48,6 @@ import org.springframework.test.context.web.WebAppConfiguration
import org.springframework.util.StreamUtils
import org.springframework.web.client.RestTemplate
import static org.junit.Assert.assertEquals
import static org.junit.Assert.assertTrue
/**
@@ -216,10 +215,11 @@ abstract class AbstractInitializrControllerIntegrationTests {
@Bean
InitializrMetadataProvider initializrMetadataProvider(InitializrProperties properties) {
def metadata = InitializrMetadataBuilder.fromInitializrProperties(properties).build()
new DefaultInitializrMetadataProvider(metadata) {
new DefaultInitializrMetadataProvider(
InitializrMetadataBuilder.fromInitializrProperties(properties).build(),
new RestTemplate()) {
@Override
protected List<DefaultMetadataElement> fetchBootVersions() {
protected void updateInitializrMetadata(InitializrMetadata metadata) {
null // Disable metadata fetching from spring.io
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2015 the original author or authors.
* Copyright 2012-2016 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.
@@ -16,38 +16,91 @@
package io.spring.initializr.web.support
import io.spring.initializr.metadata.DefaultMetadataElement
import io.spring.initializr.test.metadata.InitializrMetadataTestBuilder
import org.junit.Before
import org.junit.Test
import static org.junit.Assert.*
import org.springframework.core.io.ClassPathResource
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpMethod
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.test.web.client.MockRestServiceServer
import org.springframework.web.client.RestTemplate
import static org.junit.Assert.assertEquals
import static org.junit.Assert.assertNotNull
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo
import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus
/**
* @author Stephane Nicoll
*/
class DefaultInitializrMetadataProviderTests {
private RestTemplate restTemplate
private MockRestServiceServer mockServer
@Before
public void setUp() {
restTemplate = new RestTemplate()
mockServer = MockRestServiceServer.createServer(restTemplate);
}
@Test
void bootVersionsAreReplaced() {
def metadata = new InitializrMetadataTestBuilder()
.addBootVersion('0.0.9.RELEASE', true).addBootVersion('0.0.8.RELEASE', false).build()
assertEquals '0.0.9.RELEASE', metadata.bootVersions.default.id
def provider = new DefaultInitializrMetadataProvider(metadata)
def provider = new DefaultInitializrMetadataProvider(metadata, restTemplate)
expectJson(metadata.configuration.env.springBootMetadataUrl,
"metadata/sagan/spring-boot.json");
def updatedMetadata = provider.get()
assertNotNull updatedMetadata.bootVersions
assertFalse 'Boot versions must be set', updatedMetadata.bootVersions.content.isEmpty()
def updatedBootVersions = updatedMetadata.bootVersions.content
assertEquals 4, updatedBootVersions.size()
assertBootVersion(updatedBootVersions[0], '1.4.1 (SNAPSHOT)', false)
assertBootVersion(updatedBootVersions[1], '1.4.0', true)
assertBootVersion(updatedBootVersions[2], '1.3.8 (SNAPSHOT)', false)
assertBootVersion(updatedBootVersions[3], '1.3.7', false)
}
def defaultVersion = null
updatedMetadata.bootVersions.content.each {
assertFalse '0.0.9.RELEASE should have been removed', '0.0.9.RELEASE'.equals(it.id)
assertFalse '0.0.8.RELEASE should have been removed', '0.0.8.RELEASE'.equals(it.id)
if (it.default) {
defaultVersion = it.id
@Test
void defaultBootVersionIsAlwaysSet() {
def metadata = new InitializrMetadataTestBuilder()
.addBootVersion('0.0.9.RELEASE', true).addBootVersion('0.0.8.RELEASE', false).build()
assertEquals '0.0.9.RELEASE', metadata.bootVersions.default.id
def provider = new DefaultInitializrMetadataProvider(metadata, restTemplate)
expectJson(metadata.configuration.env.springBootMetadataUrl,
"metadata/sagan/spring-boot-no-default.json");
def updatedMetadata = provider.get()
assertNotNull updatedMetadata.bootVersions
def updatedBootVersions = updatedMetadata.bootVersions.content
assertEquals 4, updatedBootVersions.size()
assertBootVersion(updatedBootVersions[0], '1.3.1 (SNAPSHOT)', true)
assertBootVersion(updatedBootVersions[1], '1.3.0', false)
assertBootVersion(updatedBootVersions[2], '1.2.6 (SNAPSHOT)', false)
assertBootVersion(updatedBootVersions[3], '1.2.5', false)
}
private static void assertBootVersion(DefaultMetadataElement actual, String name, boolean defaultVersion) {
assertEquals name, actual.name
assertEquals defaultVersion, actual.default
}
assertNotNull 'A default boot version must be set', defaultVersion
assertEquals 'Default boot version not updated properly', defaultVersion,
updatedMetadata.bootVersions.default.id
private void expectJson(String url, String bodyPath) {
HttpHeaders httpHeaders = new HttpHeaders()
httpHeaders.setContentType(MediaType.APPLICATION_JSON)
this.mockServer.expect(requestTo(url))
.andExpect(method(HttpMethod.GET))
.andRespond(withStatus(HttpStatus.OK)
.body(new ClassPathResource(bodyPath))
.headers(httpHeaders))
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2015 the original author or authors.
* Copyright 2012-2016 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.
@@ -20,6 +20,8 @@ import io.spring.initializr.metadata.InitializrMetadata
import io.spring.initializr.metadata.InitializrMetadataBuilder
import org.junit.Test
import org.springframework.web.client.RestTemplate
import static org.junit.Assert.assertNotNull
import static org.junit.Assert.fail
@@ -32,7 +34,8 @@ class SpringBootMetadataReaderTests {
@Test
void readAvailableVersions() {
def versions = new SpringBootMetadataReader(metadata.configuration.env.springBootMetadataUrl).bootVersions
def versions = new SpringBootMetadataReader(new RestTemplate(),
metadata.configuration.env.springBootMetadataUrl).bootVersions
assertNotNull "spring boot versions should not be null", versions
boolean defaultFound
versions.each {