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..79957683ffc --- /dev/null +++ b/start-site/src/main/java/io/spring/start/site/extension/dependency/springmodulith/SpringModulithBuildCustomizer.java @@ -0,0 +1,101 @@ +/* + * 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.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; + +import java.util.Collection; +import java.util.List; + +/** + * 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) { + + var 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..ef385e1dede --- /dev/null +++ b/start-site/src/main/java/io/spring/start/site/extension/dependency/springmodulith/SpringModulithProjectGenerationConfiguration.java @@ -0,0 +1,36 @@ +/* + * 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..fc162668824 --- /dev/null +++ b/start-site/src/main/java/io/spring/start/site/extension/dependency/springmodulith/package-info.java @@ -0,0 +1,16 @@ +/* + * 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; 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..526a8e4be1e 100644 --- a/start-site/src/main/resources/application.yml +++ b/start-site/src/main/resources/application.yml @@ -139,6 +139,14 @@ 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 + version: 1.0.0-M1 + mappings: + - compatibility-range: "[3.0.0,3.2.0-M1)" + version: 1.0.0-M1 + repositories: spring-milestones spring-shell: groupId: org.springframework.shell artifactId: spring-shell-dependencies @@ -199,12 +207,26 @@ initializr: spring-releases: name: Spring Releases url: https://repo.spring.io/release + spring-milestones: + name: Spring Milestones + url: https://repo.spring.io/milestone sonatype-snapshots: name: Sonatype Snapshots url: https://oss.sonatype.org/content/repositories/snapshots/ releasesEnabled: false snapshotsEnabled: true dependencies: + - name: Architecture + content: + - name: Spring Modulith + id: modulith + group-id: org.springframework.experimental + 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: Developer Tools content: - name: GraalVM Native Support 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..b474a0774bf --- /dev/null +++ b/start-site/src/test/java/io/spring/start/site/extension/dependency/springmodulith/SpringModulithBuildCustomizerTests.java @@ -0,0 +1,117 @@ +/* + * 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 static io.spring.start.site.extension.dependency.springmodulith.SpringModulithBuildCustomizer.*; +import static org.assertj.core.api.Assertions.*; + +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 java.util.stream.Stream; + +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.Named; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestFactory; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +/** + * Tests for {@link SpringModulithBuildCustomizer}. + * + * @author Oliver Drotbohm + */ +class SpringModulithBuildCustomizerTests extends AbstractExtensionTests { + + private final SpringModulithBuildCustomizer customizer = new SpringModulithBuildCustomizer(); + + @Test + void registersCoreStarterByDefault() { + + Build build = createBuild(); + customizer.customize(build); + + assertThat(build.dependencies().ids()).contains("modulith"); + } + + @Test + void registersTestStarterByDefault() { + + Build build = createBuild(); + customizer.customize(build); + + assertThat(build.dependencies().ids()).contains("modulith-starter-test"); + } + + @Test + void registersActuatorStarterIfActuatorsIsPresent() { + + Build build = createBuild(); + build.dependencies().add("actuator"); + + customizer.customize(build); + + assertThat(build.dependencies().ids()).contains("modulith-actuator"); + } + + @TestFactory + Stream registersObservabilityStarterIfObservabilityDependencyIsPresent() { + + Stream> namedDependencies = OBSERVABILITY_DEPENDENCIES.stream().map(it -> Named.of(it, it)); + + return DynamicTest.stream(namedDependencies, it -> { + + Build build = createBuild(); + build.dependencies().add(it); + + 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); + + 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()); + } +}