diff --git a/start-site/src/main/java/io/spring/start/site/extension/dependency/springmodulith/SpringModulithBuildCustomizer.java b/start-site/src/main/java/io/spring/start/site/extension/dependency/springmodulith/SpringModulithBuildCustomizer.java new file mode 100644 index 00000000000..3fe786493e2 --- /dev/null +++ b/start-site/src/main/java/io/spring/start/site/extension/dependency/springmodulith/SpringModulithBuildCustomizer.java @@ -0,0 +1,104 @@ +/* + * Copyright 2012-2023 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 + * + * https://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.start.site.extension.dependency.springmodulith; + +import java.util.Collection; +import java.util.List; + +import io.spring.initializr.generator.buildsystem.Build; +import io.spring.initializr.generator.buildsystem.Dependency; +import io.spring.initializr.generator.buildsystem.Dependency.Builder; +import io.spring.initializr.generator.buildsystem.DependencyContainer; +import io.spring.initializr.generator.buildsystem.DependencyScope; +import io.spring.initializr.generator.spring.build.BuildCustomizer; + +/** + * Registers Spring Modulith dependencies to the build file of the project to be created, + * in particular registering integration dependencies depending on others registered for + * inclusion as well (observability and persistence). + * + * @author Oliver Drotbohm + */ +class SpringModulithBuildCustomizer implements BuildCustomizer { + + static final String GROUP_ID = "org.springframework.experimental"; + static final String BOM_ARTIFACT_ID = "spring-modulith-bom"; + + static final Collection OBSERVABILITY_DEPENDENCIES = List.of("datadog", "graphite", "influx", "new-relic", + "prometheus", "wavefront", "zipkin"); + + private static final String ARTIFACT_PREFIX = "spring-modulith-"; + + private static final Builder ACTUATOR = Dependency.withCoordinates(GROUP_ID, ARTIFACT_PREFIX + "actuator") + .scope(DependencyScope.RUNTIME); + + private static final Builder OBSERVABILITY = Dependency + .withCoordinates(GROUP_ID, ARTIFACT_PREFIX + "observability") + .scope(DependencyScope.RUNTIME); + + private static final Builder STARTER_JDBC = Dependency.withCoordinates(GROUP_ID, + ARTIFACT_PREFIX + "starter-jdbc"); + + private static final Builder STARTER_JPA = Dependency.withCoordinates(GROUP_ID, ARTIFACT_PREFIX + "starter-jpa"); + + private static final Builder STARTER_MONGODB = Dependency.withCoordinates(GROUP_ID, + ARTIFACT_PREFIX + "starter-mongodb"); + + private static final Builder TEST = Dependency.withCoordinates(GROUP_ID, ARTIFACT_PREFIX + "starter-test") + .scope(DependencyScope.TEST_COMPILE); + + @Override + public void customize(Build build) { + DependencyContainer dependencies = build.dependencies(); + + // Actuator + + if (dependencies.has("actuator")) { + dependencies.add("modulith-actuator", ACTUATOR); + } + + // Observability + + if (OBSERVABILITY_DEPENDENCIES.stream().anyMatch(dependencies::has)) { + dependencies.add("modulith-observability", OBSERVABILITY); + } + + // Event publication registry support + + addEventPublicationRegistryBackend(build); + + dependencies.add("modulith-starter-test", TEST); + } + + private void addEventPublicationRegistryBackend(Build build) { + + DependencyContainer dependencies = build.dependencies(); + + if (dependencies.has("data-mongodb")) { + dependencies.add("modulith-starter-mongodb", STARTER_MONGODB); + } + + if (dependencies.has("data-jdbc")) { + dependencies.add("modulith-starter-jdbc", STARTER_JDBC); + } + + if (dependencies.has("data-jpa")) { + dependencies.add("modulith-starter-jpa", STARTER_JPA); + } + } + +} diff --git a/start-site/src/main/java/io/spring/start/site/extension/dependency/springmodulith/SpringModulithProjectGenerationConfiguration.java b/start-site/src/main/java/io/spring/start/site/extension/dependency/springmodulith/SpringModulithProjectGenerationConfiguration.java new file mode 100644 index 00000000000..b9c2eacff77 --- /dev/null +++ b/start-site/src/main/java/io/spring/start/site/extension/dependency/springmodulith/SpringModulithProjectGenerationConfiguration.java @@ -0,0 +1,39 @@ +/* + * Copyright 2012-2023 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 + * + * https://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.start.site.extension.dependency.springmodulith; + +import io.spring.initializr.generator.condition.ConditionalOnRequestedDependency; +import io.spring.initializr.generator.project.ProjectGenerationConfiguration; + +import org.springframework.context.annotation.Bean; + +/** + * Registers {@link SpringModulithBuildCustomizer} with the context to allow selecting + * Spring Modulith dependencies. + * + * @author Oliver Drotbohm + */ +@ProjectGenerationConfiguration +@ConditionalOnRequestedDependency("modulith") +class SpringModulithProjectGenerationConfiguration { + + @Bean + SpringModulithBuildCustomizer springModulithBuildCustomizer() { + return new SpringModulithBuildCustomizer(); + } + +} diff --git a/start-site/src/main/java/io/spring/start/site/extension/dependency/springmodulith/package-info.java b/start-site/src/main/java/io/spring/start/site/extension/dependency/springmodulith/package-info.java new file mode 100644 index 00000000000..f8b21749736 --- /dev/null +++ b/start-site/src/main/java/io/spring/start/site/extension/dependency/springmodulith/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2023 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 + * + * https://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. + */ + +/** + * Extensions for generation of projects that depend on Spring Modulith. + */ +package io.spring.start.site.extension.dependency.springmodulith; diff --git a/start-site/src/main/resources/META-INF/spring.factories b/start-site/src/main/resources/META-INF/spring.factories index cf085aea047..5b483db2a06 100644 --- a/start-site/src/main/resources/META-INF/spring.factories +++ b/start-site/src/main/resources/META-INF/spring.factories @@ -25,6 +25,7 @@ io.spring.start.site.extension.dependency.springboot.SpringBootProjectGeneration io.spring.start.site.extension.dependency.springcloud.SpringCloudProjectGenerationConfiguration,\ io.spring.start.site.extension.dependency.springdata.SpringDataProjectGenerationConfiguration,\ io.spring.start.site.extension.dependency.springintegration.SpringIntegrationProjectGenerationConfiguration,\ +io.spring.start.site.extension.dependency.springmodulith.SpringModulithProjectGenerationConfiguration,\ io.spring.start.site.extension.dependency.springpulsar.SpringPulsarProjectGenerationConfiguration,\ io.spring.start.site.extension.dependency.springrestdocs.SpringRestDocsProjectGenerationConfiguration,\ io.spring.start.site.extension.dependency.sqlserver.SqlServerProjectGenerationConfiguration,\ diff --git a/start-site/src/main/resources/application.yml b/start-site/src/main/resources/application.yml index 8b8f0ccf9cb..c06ee5eb658 100644 --- a/start-site/src/main/resources/application.yml +++ b/start-site/src/main/resources/application.yml @@ -139,6 +139,13 @@ initializr: version: 3.5.0 - compatibilityRange: "[3.0.0,3.1.0-M1)" version: 4.0.0 + spring-modulith: + groupId: org.springframework.modulith + artifactId: spring-modulith-bom + mappings: + - compatibility-range: "[3.1.0,3.2.0-M1)" + version: 1.0.0-M1 + repositories: spring-milestones spring-shell: groupId: org.springframework.shell artifactId: spring-shell-dependencies @@ -252,6 +259,15 @@ initializr: links: - rel: reference href: https://docs.spring.io/spring-boot/docs/{bootVersion}/reference/htmlsingle/#features.docker-compose + - name: Spring Modulith + id: modulith + group-id: org.springframework.modulith + artifact-id: spring-modulith-starter-core + description: Support for building modular monolithic applications. + bom: spring-modulith + links: + - rel: reference + href: https://docs.spring.io/spring-modulith/docs/current/reference/html/ - name: Web content: - name: Spring Web diff --git a/start-site/src/test/java/io/spring/start/site/extension/dependency/springmodulith/SpringModulithBuildCustomizerTests.java b/start-site/src/test/java/io/spring/start/site/extension/dependency/springmodulith/SpringModulithBuildCustomizerTests.java new file mode 100644 index 00000000000..c919698a367 --- /dev/null +++ b/start-site/src/test/java/io/spring/start/site/extension/dependency/springmodulith/SpringModulithBuildCustomizerTests.java @@ -0,0 +1,109 @@ +/* + * Copyright 2012-2023 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 + * + * https://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.start.site.extension.dependency.springmodulith; + +import java.util.Collection; + +import io.spring.initializr.generator.buildsystem.Build; +import io.spring.initializr.generator.buildsystem.maven.MavenBuild; +import io.spring.initializr.generator.version.Version; +import io.spring.initializr.metadata.InitializrMetadata; +import io.spring.initializr.metadata.support.MetadataBuildItemResolver; +import io.spring.start.site.extension.AbstractExtensionTests; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link SpringModulithBuildCustomizer}. + * + * @author Oliver Drotbohm + */ +class SpringModulithBuildCustomizerTests extends AbstractExtensionTests { + + private final SpringModulithBuildCustomizer customizer = new SpringModulithBuildCustomizer(); + + @Test + void registersCoreStarterByDefault() { + Build build = createBuild(); + this.customizer.customize(build); + + assertThat(build.dependencies().ids()).contains("modulith"); + } + + @Test + void registersTestStarterByDefault() { + Build build = createBuild(); + this.customizer.customize(build); + + assertThat(build.dependencies().ids()).contains("modulith-starter-test"); + } + + @Test + void registersActuatorStarterIfActuatorsIsPresent() { + Build build = createBuild(); + build.dependencies().add("actuator"); + + this.customizer.customize(build); + + assertThat(build.dependencies().ids()).contains("modulith-actuator"); + } + + @ParameterizedTest + @MethodSource("observabilityDependencies") + void registersObservabilityStarterIfObservabilityDependencyIsPresent(String dependency) { + Build build = createBuild(); + build.dependencies().add(dependency); + + this.customizer.customize(build); + + assertThat(build.dependencies().ids()).contains("modulith-observability"); + } + + @ParameterizedTest + @ValueSource(strings = { "jdbc", "jpa", "mongodb" }) + void presenceOfSpringDataModuleAddsModuleEventStarter(String store) { + Build build = createBuild(); + build.dependencies().add("data-" + store); + + this.customizer.customize(build); + + assertThat(build.dependencies().ids()).contains("modulith-starter-" + store); + assertThat(build.boms().has("spring-modulith")); + } + + private Build createBuild() { + InitializrMetadata metadata = getMetadata(); + + Build build = new MavenBuild(new MetadataBuildItemResolver(metadata, getDefaultPlatformVersion(metadata))); + build.dependencies().add("modulith"); + + return build; + } + + private static Version getDefaultPlatformVersion(InitializrMetadata metadata) { + return Version.parse(metadata.getBootVersions().getDefault().getId()); + } + + private static Collection observabilityDependencies() { + return SpringModulithBuildCustomizer.OBSERVABILITY_DEPENDENCIES; + } + +}