mirror of
https://gitee.com/dcren/initializr.git
synced 2025-07-16 16:50:42 +08:00
Fire event if a project could not be generated
Previously, only an invalid type or an invalid dependency would lead to an exception and in such case, no event is fired at all. This commit adds validation for language and packaging as well as a new event that is fired when the project could not be generated. The metrics infrastructure has been updated to handle ProjectFailedEvent; when such an event is fired, the 'failures' counter is increased and we still record all the other metrics. Closes gh-188
This commit is contained in:
parent
3f1b4eca13
commit
f165405b26
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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.generator
|
||||
|
||||
/**
|
||||
* Event published when an error occured trying to generate a project.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.0
|
||||
*/
|
||||
class ProjectFailedEvent extends ProjectRequestEvent {
|
||||
|
||||
/**
|
||||
* The cause of the failure.
|
||||
*/
|
||||
final Exception cause
|
||||
|
||||
ProjectFailedEvent(ProjectRequest projectRequest, Exception cause) {
|
||||
super(projectRequest)
|
||||
this.cause = cause
|
||||
}
|
||||
|
||||
}
|
@ -17,26 +17,15 @@
|
||||
package io.spring.initializr.generator
|
||||
|
||||
/**
|
||||
* Event fired when a new project has been generated successfully.
|
||||
* Event published when a new project has been generated successfully.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.0
|
||||
*/
|
||||
class ProjectGeneratedEvent {
|
||||
|
||||
/**
|
||||
* The {@link ProjectRequest} used to generate the project.
|
||||
*/
|
||||
final ProjectRequest projectRequest
|
||||
|
||||
/**
|
||||
* The timestamp at which the project was generated
|
||||
*/
|
||||
final long timestamp
|
||||
class ProjectGeneratedEvent extends ProjectRequestEvent {
|
||||
|
||||
ProjectGeneratedEvent(ProjectRequest projectRequest) {
|
||||
this.projectRequest = projectRequest
|
||||
this.timestamp = System.currentTimeMillis()
|
||||
super(projectRequest)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -39,7 +39,16 @@ class ProjectGenerationMetricsListener {
|
||||
|
||||
@EventListener
|
||||
void onGeneratedProject(ProjectGeneratedEvent event) {
|
||||
def request = event.projectRequest
|
||||
handleProjectRequest(event.projectRequest)
|
||||
}
|
||||
|
||||
@EventListener
|
||||
void onFailedProject(ProjectFailedEvent event) {
|
||||
handleProjectRequest(event.projectRequest)
|
||||
increment(key('failures'))
|
||||
}
|
||||
|
||||
protected void handleProjectRequest(ProjectRequest request) {
|
||||
increment(key('requests')) // Total number of requests
|
||||
handleDependencies(request)
|
||||
handleType(request)
|
||||
|
@ -17,6 +17,7 @@
|
||||
package io.spring.initializr.generator
|
||||
|
||||
import groovy.util.logging.Slf4j
|
||||
import io.spring.initializr.InitializrException
|
||||
import io.spring.initializr.metadata.Dependency
|
||||
import io.spring.initializr.metadata.InitializrMetadataProvider
|
||||
import io.spring.initializr.util.Version
|
||||
@ -60,20 +61,30 @@ class ProjectGenerator {
|
||||
* Generate a Maven pom for the specified {@link ProjectRequest}.
|
||||
*/
|
||||
byte[] generateMavenPom(ProjectRequest request) {
|
||||
def model = initializeModel(request)
|
||||
def content = doGenerateMavenPom(model)
|
||||
publishProjectGeneratedEvent(request)
|
||||
content
|
||||
try {
|
||||
def model = initializeModel(request)
|
||||
def content = doGenerateMavenPom(model)
|
||||
publishProjectGeneratedEvent(request)
|
||||
content
|
||||
} catch (InitializrException ex) {
|
||||
publishProjectFailedEvent(request, ex)
|
||||
throw ex
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a Gradle build file for the specified {@link ProjectRequest}.
|
||||
*/
|
||||
byte[] generateGradleBuild(ProjectRequest request) {
|
||||
def model = initializeModel(request)
|
||||
def content = doGenerateGradleBuild(model)
|
||||
publishProjectGeneratedEvent(request)
|
||||
content
|
||||
try {
|
||||
def model = initializeModel(request)
|
||||
def content = doGenerateGradleBuild(model)
|
||||
publishProjectGeneratedEvent(request)
|
||||
content
|
||||
} catch (InitializrException ex) {
|
||||
publishProjectFailedEvent(request, ex)
|
||||
throw ex
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -81,6 +92,15 @@ class ProjectGenerator {
|
||||
* a directory containing the project.
|
||||
*/
|
||||
File generateProjectStructure(ProjectRequest request) {
|
||||
try {
|
||||
doGenerateProjectStructure(request)
|
||||
} catch (InitializrException ex) {
|
||||
publishProjectFailedEvent(request, ex)
|
||||
throw ex
|
||||
}
|
||||
}
|
||||
|
||||
protected File doGenerateProjectStructure(ProjectRequest request) {
|
||||
def model = initializeModel(request)
|
||||
|
||||
def rootDir = File.createTempFile('tmp', '', new File(tmpdir))
|
||||
@ -171,6 +191,11 @@ class ProjectGenerator {
|
||||
eventPublisher.publishEvent(event)
|
||||
}
|
||||
|
||||
private void publishProjectFailedEvent(ProjectRequest request, Exception cause) {
|
||||
ProjectFailedEvent event = new ProjectFailedEvent(request, cause)
|
||||
eventPublisher.publishEvent(event)
|
||||
}
|
||||
|
||||
protected Map initializeModel(ProjectRequest request) {
|
||||
Assert.notNull request.bootVersion, 'boot version must not be null'
|
||||
def model = [:]
|
||||
|
@ -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.
|
||||
@ -137,6 +137,18 @@ class ProjectRequest {
|
||||
this.build = buildTag
|
||||
}
|
||||
}
|
||||
if (this.packaging) {
|
||||
def packaging = metadata.packagings.get(this.packaging)
|
||||
if (!packaging) {
|
||||
throw new InvalidProjectRequestException("Unknown packaging '${this.packaging}' check project metadata")
|
||||
}
|
||||
}
|
||||
if (this.language) {
|
||||
def language = metadata.languages.get(this.language)
|
||||
if (!language) {
|
||||
throw new InvalidProjectRequestException("Unknown language '${this.language}' check project metadata")
|
||||
}
|
||||
}
|
||||
|
||||
if (!applicationName) {
|
||||
this.applicationName = metadata.configuration.generateApplicationName(this.name)
|
||||
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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.generator
|
||||
|
||||
/**
|
||||
* Event published when a {@link ProjectRequest} has been processed.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.0
|
||||
* @see ProjectGeneratedEvent
|
||||
* @see ProjectFailedEvent
|
||||
*/
|
||||
abstract class ProjectRequestEvent {
|
||||
|
||||
/**
|
||||
* The {@link ProjectRequest} used to generate the project.
|
||||
*/
|
||||
final ProjectRequest projectRequest
|
||||
|
||||
/**
|
||||
* The timestamp at which the request was processed.
|
||||
*/
|
||||
final long timestamp
|
||||
|
||||
protected ProjectRequestEvent(ProjectRequest projectRequest) {
|
||||
this.projectRequest = projectRequest
|
||||
this.timestamp = System.currentTimeMillis()
|
||||
}
|
||||
|
||||
}
|
@ -47,16 +47,25 @@ class ProjectGenerationMetricsListenerTests {
|
||||
void projectGenerationCount() {
|
||||
def request = initialize()
|
||||
request.resolve(metadata)
|
||||
fireEvent(request)
|
||||
fireProjectGeneratedEvent(request)
|
||||
metricsAssert.hasValue(1, 'initializr.requests')
|
||||
}
|
||||
|
||||
@Test
|
||||
void projectGenerationCountWithFailure() {
|
||||
def request = initialize()
|
||||
request.resolve(metadata)
|
||||
fireProjectFailedEvent(request)
|
||||
metricsAssert.hasValue(1, 'initializr.requests')
|
||||
metricsAssert.hasValue(1, 'initializr.failures')
|
||||
}
|
||||
|
||||
@Test
|
||||
void dependencies() {
|
||||
def request = initialize()
|
||||
request.style << 'security' << 'spring-data'
|
||||
request.resolve(metadata)
|
||||
fireEvent(request)
|
||||
fireProjectGeneratedEvent(request)
|
||||
metricsAssert.hasValue(1, 'initializr.dependency.security',
|
||||
'initializr.dependency.spring-data')
|
||||
}
|
||||
@ -65,7 +74,7 @@ class ProjectGenerationMetricsListenerTests {
|
||||
void noDependencies() {
|
||||
def request = initialize()
|
||||
request.resolve(metadata)
|
||||
fireEvent(request)
|
||||
fireProjectGeneratedEvent(request)
|
||||
metricsAssert.hasNoValue('initializr.dependency.')
|
||||
}
|
||||
|
||||
@ -75,7 +84,7 @@ class ProjectGenerationMetricsListenerTests {
|
||||
request.style << 'spring-data'
|
||||
request.packaging = 'war'
|
||||
request.resolve(metadata)
|
||||
fireEvent(request)
|
||||
fireProjectGeneratedEvent(request)
|
||||
metricsAssert.hasValue(1, 'initializr.dependency.web',
|
||||
'initializr.dependency.spring-data')
|
||||
}
|
||||
@ -91,7 +100,7 @@ class ProjectGenerationMetricsListenerTests {
|
||||
request.initialize(metadata)
|
||||
request.style << 'foo-old'
|
||||
request.resolve(metadata)
|
||||
fireEvent(request)
|
||||
fireProjectGeneratedEvent(request)
|
||||
metricsAssert.hasValue(1, 'initializr.dependency.foo') // standard id is used
|
||||
}
|
||||
|
||||
@ -99,7 +108,7 @@ class ProjectGenerationMetricsListenerTests {
|
||||
void defaultType() {
|
||||
def request = initialize()
|
||||
request.resolve(metadata)
|
||||
fireEvent(request)
|
||||
fireProjectGeneratedEvent(request)
|
||||
metricsAssert.hasValue(1, 'initializr.type.maven-project')
|
||||
}
|
||||
|
||||
@ -108,7 +117,7 @@ class ProjectGenerationMetricsListenerTests {
|
||||
def request = initialize()
|
||||
request.type = 'gradle-build'
|
||||
request.resolve(metadata)
|
||||
fireEvent(request)
|
||||
fireProjectGeneratedEvent(request)
|
||||
metricsAssert.hasValue(1, 'initializr.type.gradle-build')
|
||||
}
|
||||
|
||||
@ -116,7 +125,7 @@ class ProjectGenerationMetricsListenerTests {
|
||||
void defaultPackaging() {
|
||||
def request = initialize()
|
||||
request.resolve(metadata)
|
||||
fireEvent(request)
|
||||
fireProjectGeneratedEvent(request)
|
||||
metricsAssert.hasValue(1, 'initializr.packaging.jar')
|
||||
}
|
||||
|
||||
@ -125,7 +134,7 @@ class ProjectGenerationMetricsListenerTests {
|
||||
def request = initialize()
|
||||
request.packaging = 'war'
|
||||
request.resolve(metadata)
|
||||
fireEvent(request)
|
||||
fireProjectGeneratedEvent(request)
|
||||
metricsAssert.hasValue(1, 'initializr.packaging.war')
|
||||
}
|
||||
|
||||
@ -133,7 +142,7 @@ class ProjectGenerationMetricsListenerTests {
|
||||
void defaultJavaVersion() {
|
||||
def request = initialize()
|
||||
request.resolve(metadata)
|
||||
fireEvent(request)
|
||||
fireProjectGeneratedEvent(request)
|
||||
metricsAssert.hasValue(1, 'initializr.java_version.1_8')
|
||||
}
|
||||
|
||||
@ -142,7 +151,7 @@ class ProjectGenerationMetricsListenerTests {
|
||||
def request = initialize()
|
||||
request.javaVersion = '1.7'
|
||||
request.resolve(metadata)
|
||||
fireEvent(request)
|
||||
fireProjectGeneratedEvent(request)
|
||||
metricsAssert.hasValue(1, 'initializr.java_version.1_7')
|
||||
}
|
||||
|
||||
@ -150,7 +159,7 @@ class ProjectGenerationMetricsListenerTests {
|
||||
void defaultLanguage() {
|
||||
def request = initialize()
|
||||
request.resolve(metadata)
|
||||
fireEvent(request)
|
||||
fireProjectGeneratedEvent(request)
|
||||
metricsAssert.hasValue(1, 'initializr.language.java')
|
||||
}
|
||||
|
||||
@ -159,7 +168,7 @@ class ProjectGenerationMetricsListenerTests {
|
||||
def request = initialize()
|
||||
request.language = 'groovy'
|
||||
request.resolve(metadata)
|
||||
fireEvent(request)
|
||||
fireProjectGeneratedEvent(request)
|
||||
metricsAssert.hasValue(1, 'initializr.language.groovy')
|
||||
}
|
||||
|
||||
@ -167,7 +176,7 @@ class ProjectGenerationMetricsListenerTests {
|
||||
void defaultBootVersion() {
|
||||
def request = initialize()
|
||||
request.resolve(metadata)
|
||||
fireEvent(request)
|
||||
fireProjectGeneratedEvent(request)
|
||||
metricsAssert.hasValue(1, 'initializr.boot_version.1_2_3_RELEASE')
|
||||
}
|
||||
|
||||
@ -176,7 +185,7 @@ class ProjectGenerationMetricsListenerTests {
|
||||
def request = initialize()
|
||||
request.bootVersion = '1.0.2.RELEASE'
|
||||
request.resolve(metadata)
|
||||
fireEvent(request)
|
||||
fireProjectGeneratedEvent(request)
|
||||
metricsAssert.hasValue(1, 'initializr.boot_version.1_0_2_RELEASE')
|
||||
}
|
||||
|
||||
@ -191,7 +200,7 @@ class ProjectGenerationMetricsListenerTests {
|
||||
request.bootVersion = '1.0.2.RELEASE'
|
||||
|
||||
request.resolve(metadata)
|
||||
fireEvent(request)
|
||||
fireProjectGeneratedEvent(request)
|
||||
metricsAssert.hasValue(1, 'initializr.requests',
|
||||
'initializr.dependency.web', 'initializr.dependency.security',
|
||||
'initializr.type.gradle-project', 'initializr.packaging.jar',
|
||||
@ -204,24 +213,28 @@ class ProjectGenerationMetricsListenerTests {
|
||||
def request = initialize()
|
||||
request.style << 'security' << 'spring-data'
|
||||
request.resolve(metadata)
|
||||
fireEvent(request)
|
||||
fireProjectGeneratedEvent(request)
|
||||
metricsAssert.hasValue(1, 'initializr.requests',
|
||||
'initializr.dependency.security', 'initializr.dependency.spring-data')
|
||||
|
||||
def anotherRequest = initialize()
|
||||
anotherRequest.style << 'web' << 'spring-data'
|
||||
anotherRequest.resolve(metadata)
|
||||
fireEvent(anotherRequest)
|
||||
fireProjectGeneratedEvent(anotherRequest)
|
||||
metricsAssert.hasValue(2, 'initializr.dependency.spring-data',
|
||||
'initializr.dependency.spring-data')
|
||||
metricsAssert.hasValue(1, 'initializr.dependency.web',
|
||||
'initializr.dependency.security')
|
||||
}
|
||||
|
||||
private fireEvent(ProjectRequest projectRequest) {
|
||||
private fireProjectGeneratedEvent(ProjectRequest projectRequest) {
|
||||
listener.onGeneratedProject(new ProjectGeneratedEvent(projectRequest))
|
||||
}
|
||||
|
||||
private fireProjectFailedEvent(ProjectRequest projectRequest) {
|
||||
listener.onFailedProject(new ProjectFailedEvent(projectRequest, null))
|
||||
}
|
||||
|
||||
private ProjectRequest initialize() {
|
||||
def request = new ProjectRequest()
|
||||
request.initialize(metadata)
|
||||
|
@ -36,6 +36,9 @@ import org.springframework.context.ApplicationEventPublisher
|
||||
import org.springframework.context.annotation.ComponentScan
|
||||
import org.springframework.context.annotation.Configuration
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString
|
||||
import static org.junit.Assert.assertThat
|
||||
import static org.junit.Assert.fail
|
||||
import static org.mockito.Matchers.argThat
|
||||
import static org.mockito.Mockito.mock
|
||||
import static org.mockito.Mockito.times
|
||||
@ -67,14 +70,14 @@ class ProjectGeneratorTests {
|
||||
def request = createProjectRequest('web')
|
||||
generateMavenPom(request).hasNoRepository()
|
||||
.hasSpringBootStarterDependency('web')
|
||||
verify(eventPublisher, times(1)).publishEvent(argThat(new EventMatcher(request)))
|
||||
verify(eventPublisher, times(1)).publishEvent(argThat(new ProjectGeneratedEventMatcher(request)))
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultGradleBuild() {
|
||||
def request = createProjectRequest('web')
|
||||
generateGradleBuild(request)
|
||||
verify(eventPublisher, times(1)).publishEvent(argThat(new EventMatcher(request)))
|
||||
verify(eventPublisher, times(1)).publishEvent(argThat(new ProjectGeneratedEventMatcher(request)))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -82,7 +85,7 @@ class ProjectGeneratorTests {
|
||||
def request = createProjectRequest('web')
|
||||
generateProject(request).isJavaProject().isMavenProject().pomAssert()
|
||||
.hasNoRepository().hasSpringBootStarterDependency('web')
|
||||
verify(eventPublisher, times(1)).publishEvent(argThat(new EventMatcher(request)))
|
||||
verify(eventPublisher, times(1)).publishEvent(argThat(new ProjectGeneratedEventMatcher(request)))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -523,6 +526,45 @@ class ProjectGeneratorTests {
|
||||
.hasDependenciesCount(3)
|
||||
}
|
||||
|
||||
@Test
|
||||
void invalidType() {
|
||||
def request = createProjectRequest('web')
|
||||
request.type = 'foo-bar'
|
||||
try {
|
||||
generateMavenPom(request)
|
||||
fail("Should have failed to generate project")
|
||||
} catch (InvalidProjectRequestException ex) {
|
||||
assertThat ex.message, containsString('foo-bar')
|
||||
verify(eventPublisher, times(1)).publishEvent(argThat(new ProjectFailedEventMatcher(request, ex)))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void invalidPackaging() {
|
||||
def request = createProjectRequest('web')
|
||||
request.packaging = 'foo-bar'
|
||||
try {
|
||||
generateGradleBuild(request)
|
||||
fail("Should have failed to generate project")
|
||||
} catch (InvalidProjectRequestException ex) {
|
||||
assertThat ex.message, containsString('foo-bar')
|
||||
verify(eventPublisher, times(1)).publishEvent(argThat(new ProjectFailedEventMatcher(request, ex)))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void invalidLanguage() {
|
||||
def request = createProjectRequest('web')
|
||||
request.language = 'foo-bar'
|
||||
try {
|
||||
generateProject(request)
|
||||
fail("Should have failed to generate project")
|
||||
} catch (InvalidProjectRequestException ex) {
|
||||
assertThat ex.message, containsString('foo-bar')
|
||||
verify(eventPublisher, times(1)).publishEvent(argThat(new ProjectFailedEventMatcher(request, ex)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PomAssert generateMavenPom(ProjectRequest request) {
|
||||
def content = new String(projectGenerator.generateMavenPom(request))
|
||||
@ -555,18 +597,35 @@ class ProjectGeneratorTests {
|
||||
}
|
||||
}
|
||||
|
||||
private static class EventMatcher extends ArgumentMatcher<ProjectGeneratedEvent> {
|
||||
private static class ProjectGeneratedEventMatcher extends ArgumentMatcher<ProjectGeneratedEvent> {
|
||||
|
||||
private final ProjectRequest request
|
||||
|
||||
EventMatcher(ProjectRequest request) {
|
||||
ProjectGeneratedEventMatcher(ProjectRequest request) {
|
||||
this.request = request
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean matches(Object argument) {
|
||||
ProjectGeneratedEvent event = (ProjectGeneratedEvent) argument
|
||||
return request.equals(event.getProjectRequest())
|
||||
return request.equals(event.projectRequest)
|
||||
}
|
||||
}
|
||||
|
||||
private static class ProjectFailedEventMatcher extends ArgumentMatcher<ProjectFailedEvent> {
|
||||
|
||||
private final ProjectRequest request
|
||||
private final Exception cause
|
||||
|
||||
ProjectFailedEventMatcher(ProjectRequest request, Exception cause) {
|
||||
this.request = request
|
||||
this.cause = cause
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean matches(Object argument) {
|
||||
ProjectFailedEvent event = (ProjectFailedEvent) argument
|
||||
return request.equals(event.projectRequest) && cause.equals(event.cause)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user