diff --git a/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/AbstractGrpcGradleBuildCustomizer.java b/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/AbstractGrpcGradleBuildCustomizer.java new file mode 100644 index 0000000000..8717c165d4 --- /dev/null +++ b/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/AbstractGrpcGradleBuildCustomizer.java @@ -0,0 +1,51 @@ +/* + * Copyright 2012-2024 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.springgrpc; + +import io.spring.initializr.generator.buildsystem.gradle.GradleBuild; +import io.spring.initializr.generator.buildsystem.gradle.GradleExtensionContainer; +import io.spring.initializr.generator.spring.build.BuildCustomizer; + +/** + * Abstract base class for {@link BuildCustomizer} to deal withj Gradle based gRPC + * projects. + * + * @author Moritz Halbritter + */ +abstract class AbstractGrpcGradleBuildCustomizer implements BuildCustomizer { + + private static final String GRPC_PLUGIN_VERSION = "0.9.4"; + + private final char quote; + + AbstractGrpcGradleBuildCustomizer(char quote) { + this.quote = quote; + } + + @Override + public void customize(GradleBuild build) { + build.plugins().add("com.google.protobuf", (plugin) -> plugin.setVersion(GRPC_PLUGIN_VERSION)); + customizeExtensions(build.extensions()); + } + + protected abstract void customizeExtensions(GradleExtensionContainer extensions); + + protected String quote(String value) { + return this.quote + value + this.quote; + } + +} diff --git a/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/GrpcAdditionalDependenciesBuildCustomizer.java b/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/GrpcAdditionalDependenciesBuildCustomizer.java new file mode 100644 index 0000000000..0b4f1a8e64 --- /dev/null +++ b/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/GrpcAdditionalDependenciesBuildCustomizer.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012-2024 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.springgrpc; + +import io.spring.initializr.generator.buildsystem.Build; +import io.spring.initializr.generator.buildsystem.DependencyScope; +import io.spring.initializr.generator.spring.build.BuildCustomizer; + +/** + * {@link BuildCustomizer} to add additional dependencies for Spring gRPC. + * + * @author Moritz Halbritter + */ +class GrpcAdditionalDependenciesBuildCustomizer implements BuildCustomizer { + + @Override + public void customize(Build build) { + build.dependencies().add("grpc-services", "io.grpc", "grpc-services", DependencyScope.COMPILE); + build.dependencies() + .add("spring-grpc-test", "org.springframework.grpc", "spring-grpc-test", DependencyScope.TEST_COMPILE); + } + +} diff --git a/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/GrpcGradleGroovyBuildCustomizer.java b/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/GrpcGradleGroovyBuildCustomizer.java new file mode 100644 index 0000000000..f3f4f120b8 --- /dev/null +++ b/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/GrpcGradleGroovyBuildCustomizer.java @@ -0,0 +1,45 @@ +/* + * Copyright 2012-2024 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.springgrpc; + +import io.spring.initializr.generator.buildsystem.gradle.GradleExtensionContainer; +import io.spring.initializr.generator.spring.build.BuildCustomizer; + +/** + * {@link BuildCustomizer} to customize the Groovy DSL Gradle build to build gRPC + * projects. + * + * @author Moritz Halbritter + */ +class GrpcGradleGroovyBuildCustomizer extends AbstractGrpcGradleBuildCustomizer { + + GrpcGradleGroovyBuildCustomizer() { + super('\''); + } + + @Override + protected void customizeExtensions(GradleExtensionContainer extensions) { + extensions.customize("protobuf", (protobuf) -> { + protobuf.nested("protoc", (protoc) -> protoc.attribute("artifact", quote("com.google.protobuf:protoc"))); + protobuf.nested("plugins", (plugins) -> plugins.nested("grpc", + (grpc) -> grpc.attribute("artifact", quote("io.grpc:protoc-gen-grpc-java")))); + protobuf.nested("generateProtoTasks", (generateProtoTasks) -> generateProtoTasks.nested("all()*.plugins", + (plugins) -> plugins.nested("grpc", (grpc) -> grpc.invoke("option", quote("jakarta_omit"))))); + }); + } + +} diff --git a/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/GrpcGradleKotlinBuildCustomizer.java b/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/GrpcGradleKotlinBuildCustomizer.java new file mode 100644 index 0000000000..faf2dc4b5a --- /dev/null +++ b/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/GrpcGradleKotlinBuildCustomizer.java @@ -0,0 +1,48 @@ +/* + * Copyright 2012-2024 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.springgrpc; + +import io.spring.initializr.generator.buildsystem.gradle.GradleExtensionContainer; +import io.spring.initializr.generator.spring.build.BuildCustomizer; + +/** + * {@link BuildCustomizer} to customize the Kotlin DSL Gradle build to build gRPC + * projects. + * + * @author Moritz Halbritter + */ +class GrpcGradleKotlinBuildCustomizer extends AbstractGrpcGradleBuildCustomizer { + + GrpcGradleKotlinBuildCustomizer() { + super('\"'); + } + + @Override + protected void customizeExtensions(GradleExtensionContainer extensions) { + extensions.customize("protobuf", (protobuf) -> { + protobuf.nested("protoc", (protoc) -> protoc.attribute("artifact", quote("com.google.protobuf:protoc"))); + protobuf.importType("com.google.protobuf.gradle.id"); + protobuf.nested("plugins", (plugins) -> plugins.nested("id(\"grpc\")", + (grpc) -> grpc.attribute("artifact", quote("io.grpc:protoc-gen-grpc-java")))); + protobuf.nested("generateProtoTasks", + (generateProtoTasks) -> generateProtoTasks.nested("all().forEach", + (forEach) -> forEach.nested("it.plugins", (plugins) -> plugins.nested("id(\"grpc\")", + (grpc) -> grpc.invoke("option", quote("jakarta_omit")))))); + }); + } + +} diff --git a/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/GrpcMavenBuildCustomizer.java b/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/GrpcMavenBuildCustomizer.java new file mode 100644 index 0000000000..b0304b1321 --- /dev/null +++ b/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/GrpcMavenBuildCustomizer.java @@ -0,0 +1,87 @@ +/* + * Copyright 2012-2024 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.springgrpc; + +import io.spring.initializr.generator.buildsystem.PropertyContainer; +import io.spring.initializr.generator.buildsystem.maven.MavenBuild; +import io.spring.initializr.generator.buildsystem.maven.MavenPluginContainer; +import io.spring.initializr.generator.spring.build.BuildCustomizer; +import io.spring.initializr.generator.version.VersionProperty; + +/** + * {@link BuildCustomizer} to customize the Maven build to build gRPC projects. + * + * @author Moritz Halbritter + */ +class GrpcMavenBuildCustomizer implements BuildCustomizer { + + private static final String OS_PLUGIN_VERSION = "1.7.1"; + + private static final String PROTOBUF_PLUGIN_VERSION = "0.6.1"; + + private final String protobufJavaVersion; + + private final String grpcVersion; + + GrpcMavenBuildCustomizer(String protobufJavaVersion, String grpcVersion) { + this.protobufJavaVersion = protobufJavaVersion; + this.grpcVersion = grpcVersion; + } + + @Override + public void customize(MavenBuild build) { + VersionProperty protobufJava = VersionProperty.of("protobuf-java.version"); + VersionProperty grpc = VersionProperty.of("grpc.version"); + addVersionProperties(build.properties(), protobufJava, grpc); + addOsPlugin(build.plugins()); + addProtobufPlugin(build.plugins(), protobufJava, grpc); + } + + private void addVersionProperties(PropertyContainer properties, VersionProperty protobufJava, + VersionProperty grpc) { + properties.version(protobufJava, this.protobufJavaVersion); + properties.version(grpc, this.grpcVersion); + } + + private void addOsPlugin(MavenPluginContainer plugins) { + plugins.add("kr.motd.maven", "os-maven-plugin", (plugin) -> { + plugin.version(OS_PLUGIN_VERSION); + plugin.execution("initialize", (execution) -> { + execution.phase("initialize"); + execution.goal("detect"); + }); + }); + } + + private void addProtobufPlugin(MavenPluginContainer plugins, VersionProperty protobufJava, VersionProperty grpc) { + plugins.add("org.xolstice.maven.plugins", "protobuf-maven-plugin", (plugin) -> { + plugin.version(PROTOBUF_PLUGIN_VERSION); + plugin.configuration((configuration) -> { + configuration.add("protocArtifact", "com.google.protobuf:protoc:${%s}:exe:${os.detected.classifier}" + .formatted(protobufJava.toStandardFormat())); + configuration.add("pluginId", "grpc-java"); + configuration.add("pluginArtifact", "io.grpc:protoc-gen-grpc-java:${%s}:exe:${os.detected.classifier}" + .formatted(grpc.toStandardFormat())); + }); + plugin.execution("compile", (execution) -> { + execution.goal("compile").goal("compile-custom"); + execution.configuration((configuration) -> configuration.add("pluginParameter", "jakarta_omit")); + }); + }); + } + +} diff --git a/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/GrpcProjectContributor.java b/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/GrpcProjectContributor.java new file mode 100644 index 0000000000..13a3cdfb34 --- /dev/null +++ b/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/GrpcProjectContributor.java @@ -0,0 +1,38 @@ +/* + * Copyright 2012-2024 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.springgrpc; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import io.spring.initializr.generator.project.contributor.ProjectContributor; + +/** + * A {@link ProjectContributor} that creates the "src/main/proto" directory. + * + * @author Moritz Halbritter + */ +class GrpcProjectContributor implements ProjectContributor { + + @Override + public void contribute(Path projectRoot) throws IOException { + Path protoDirectory = projectRoot.resolve("src/main/proto"); + Files.createDirectories(protoDirectory); + } + +} diff --git a/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/GrpcVersionResolver.java b/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/GrpcVersionResolver.java new file mode 100644 index 0000000000..992c6c304b --- /dev/null +++ b/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/GrpcVersionResolver.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2024 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.springgrpc; + +import java.util.Map; + +import io.spring.initializr.versionresolver.MavenVersionResolver; + +import org.springframework.util.function.SingletonSupplier; + +/** + * Resolves dependency versions from 'org.springframework.grpc:spring-grpc-dependencies'. + * + * @author Moritz Halbritter + */ +class GrpcVersionResolver { + + private final SingletonSupplier> versions; + + GrpcVersionResolver(MavenVersionResolver versionResolver, String springGrpcVersion) { + this.versions = SingletonSupplier.of(() -> versionResolver.resolveDependencies("org.springframework.grpc", + "spring-grpc-dependencies", springGrpcVersion)); + } + + String resolveProtobufJavaVersion() { + return this.versions.obtain().get("com.google.protobuf:protobuf-java"); + } + + String resolveGrpcVersion() { + return this.versions.obtain().get("io.grpc:grpc-core"); + } + +} diff --git a/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/SpringGrpcProjectGenerationConfiguration.java b/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/SpringGrpcProjectGenerationConfiguration.java new file mode 100644 index 0000000000..f9f0047843 --- /dev/null +++ b/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/SpringGrpcProjectGenerationConfiguration.java @@ -0,0 +1,80 @@ +/* + * Copyright 2012-2024 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.springgrpc; + +import io.spring.initializr.generator.buildsystem.gradle.GradleBuildSystem; +import io.spring.initializr.generator.buildsystem.maven.MavenBuildSystem; +import io.spring.initializr.generator.condition.ConditionalOnBuildSystem; +import io.spring.initializr.generator.condition.ConditionalOnRequestedDependency; +import io.spring.initializr.generator.project.ProjectDescription; +import io.spring.initializr.generator.project.ProjectGenerationConfiguration; +import io.spring.initializr.metadata.InitializrMetadata; +import io.spring.initializr.versionresolver.MavenVersionResolver; + +import org.springframework.context.annotation.Bean; + +/** + * Configuration for generation of projects that depend on Spring gRPC. + * + * @author Moritz Halbritter + */ +@ProjectGenerationConfiguration +@ConditionalOnRequestedDependency("spring-grpc") +class SpringGrpcProjectGenerationConfiguration { + + @Bean + GrpcVersionResolver grpcVersionResolver(ProjectDescription description, InitializrMetadata metadata, + MavenVersionResolver versionResolver) { + String springGrpcVersion = metadata.getConfiguration() + .getEnv() + .getBoms() + .get("spring-grpc") + .resolve(description.getPlatformVersion()) + .getVersion(); + return new GrpcVersionResolver(versionResolver, springGrpcVersion); + } + + @Bean + GrpcAdditionalDependenciesBuildCustomizer grpcAdditionalDependenciesBuildCustomizer() { + return new GrpcAdditionalDependenciesBuildCustomizer(); + } + + @Bean + @ConditionalOnBuildSystem(value = GradleBuildSystem.ID, dialect = GradleBuildSystem.DIALECT_GROOVY) + GrpcGradleGroovyBuildCustomizer grpcGradleGroovyBuildCustomizer() { + return new GrpcGradleGroovyBuildCustomizer(); + } + + @Bean + @ConditionalOnBuildSystem(value = GradleBuildSystem.ID, dialect = GradleBuildSystem.DIALECT_KOTLIN) + GrpcGradleKotlinBuildCustomizer grpcGradleKotlinBuildCustomizer() { + return new GrpcGradleKotlinBuildCustomizer(); + } + + @Bean + @ConditionalOnBuildSystem(MavenBuildSystem.ID) + GrpcMavenBuildCustomizer grpcMavenBuildCustomizer(GrpcVersionResolver versionResolver) { + return new GrpcMavenBuildCustomizer(versionResolver.resolveProtobufJavaVersion(), + versionResolver.resolveGrpcVersion()); + } + + @Bean + GrpcProjectContributor grpcProjectContributor() { + return new GrpcProjectContributor(); + } + +} diff --git a/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/package-info.java b/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/package-info.java new file mode 100644 index 0000000000..6735fc2e50 --- /dev/null +++ b/start-site/src/main/java/io/spring/start/site/extension/dependency/springgrpc/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2024 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 gRPC. + */ +package io.spring.start.site.extension.dependency.springgrpc; diff --git a/start-site/src/main/resources/META-INF/spring.factories b/start-site/src/main/resources/META-INF/spring.factories index d4480adf3f..864a5e907f 100644 --- a/start-site/src/main/resources/META-INF/spring.factories +++ b/start-site/src/main/resources/META-INF/spring.factories @@ -43,6 +43,7 @@ io.spring.start.site.extension.dependency.springazure.SpringAzureTestcontainersP io.spring.start.site.extension.dependency.springboot.SpringBootProjectGenerationConfiguration,\ io.spring.start.site.extension.dependency.springcloud.SpringCloudProjectGenerationConfiguration,\ io.spring.start.site.extension.dependency.springdata.SpringDataProjectGenerationConfiguration,\ +io.spring.start.site.extension.dependency.springgrpc.SpringGrpcProjectGenerationConfiguration,\ io.spring.start.site.extension.dependency.springintegration.SpringIntegrationProjectGenerationConfiguration,\ io.spring.start.site.extension.dependency.springkafka.SpringKafkaProjectGenerationConfiguration,\ io.spring.start.site.extension.dependency.springmodulith.SpringModulithProjectGenerationConfiguration,\ diff --git a/start-site/src/main/resources/application.yml b/start-site/src/main/resources/application.yml index fd9bfc88e7..a4ce25083f 100644 --- a/start-site/src/main/resources/application.yml +++ b/start-site/src/main/resources/application.yml @@ -119,6 +119,14 @@ initializr: mappings: - compatibilityRange: "[3.3.0,3.5.0-M1)" version: 4.2.0 + spring-grpc: + groupId: org.springframework.grpc + artifactId: spring-grpc-dependencies + versionProperty: spring-grpc.version + mappings: + - compatibilityRange: "[3.4.0,3.5.0-M1)" + version: 0.3.0-SNAPSHOT + repositories: spring-snapshots spring-modulith: groupId: org.springframework.modulith artifactId: spring-modulith-bom @@ -891,6 +899,19 @@ initializr: links: - rel: reference href: https://docs.spring.io/spring-shell/reference/index.html + - name: Spring gRPC [Experimental] + id: spring-grpc + groupId: org.springframework.grpc + artifactId: spring-grpc-spring-boot-starter + compatibilityRange: "[3.4.0,3.5.0-M1)" + description: Experimental support for gRPC, a high performance, open source universal RPC framework. + bom: spring-grpc + links: + - rel: reference + href: https://docs.spring.io/spring-grpc/reference/index.html + - rel: sample + href: https://github.com/spring-projects-experimental/spring-grpc/tree/main/samples + description: Various sample apps using Spring gRPC - name: Ops content: - name: Spring Boot Actuator diff --git a/start-site/src/test/java/io/spring/start/site/extension/dependency/springgrpc/SpringGrpcProjectGenerationConfigurationTests.java b/start-site/src/test/java/io/spring/start/site/extension/dependency/springgrpc/SpringGrpcProjectGenerationConfigurationTests.java new file mode 100644 index 0000000000..a4dbc8c0b9 --- /dev/null +++ b/start-site/src/test/java/io/spring/start/site/extension/dependency/springgrpc/SpringGrpcProjectGenerationConfigurationTests.java @@ -0,0 +1,175 @@ +/* + * Copyright 2012-2024 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.springgrpc; + +import io.spring.initializr.metadata.Dependency; +import io.spring.initializr.web.project.ProjectRequest; +import io.spring.start.site.extension.AbstractExtensionTests; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link SpringGrpcProjectGenerationConfiguration}. + * + * @author Moritz Halbritter + */ +class SpringGrpcProjectGenerationConfigurationTests extends AbstractExtensionTests { + + private static final String SPRING_GRPC = "spring-grpc"; + + @Test + void shouldDoNothingIfSpringGrpcIsntSelected() { + ProjectRequest request = createProjectRequest("web"); + assertThat(mavenPom(request)).doesNotHaveDependency("io.grpc", "grpc-services") + .doesNotHaveDependency("org.springframework.grpc", "spring-grpc-test") + .doesNotContain("os-maven-plugin") + .doesNotContain("protobuf-maven-plugin") + .doesNotHaveProperty("grpc.version") + .doesNotHaveProperty("protobuf-java.version"); + assertThat(generateProject(request)).doesNotContainDirectories("src/main/proto"); + } + + @Test + void shouldAddAdditionalDependenciesForMaven() { + ProjectRequest request = createProjectRequest(SPRING_GRPC); + assertThat(mavenPom(request)).hasDependency("io.grpc", "grpc-services", null, Dependency.SCOPE_COMPILE) + .hasDependency("org.springframework.grpc", "spring-grpc-test", null, Dependency.SCOPE_TEST); + } + + @Test + void shouldAddAdditionalDependenciesForGradle() { + ProjectRequest request = createProjectRequest(SPRING_GRPC); + request.setType("gradle-project"); + assertThat(gradleBuild(request)).contains("implementation 'io.grpc:grpc-services'") + .contains("testImplementation 'org.springframework.grpc:spring-grpc-test'"); + } + + @Test + void shouldAddGrpcPluginAndConfigurationForGradleGroovy() { + ProjectRequest request = createProjectRequest(SPRING_GRPC); + request.setType("gradle-project"); + assertThat(gradleBuild(request)).hasPlugin("com.google.protobuf", "0.9.4").containsIgnoringWhitespaces(""" + protobuf { + protoc { + artifact = 'com.google.protobuf:protoc' + } + plugins { + grpc { + artifact = 'io.grpc:protoc-gen-grpc-java' + } + } + generateProtoTasks { + all()*.plugins { + grpc { + option 'jakarta_omit' + } + } + } + } + """); + } + + @Test + void shouldAddGrpcPluginAndConfigurationForGradleKotlin() { + ProjectRequest request = createProjectRequest(SPRING_GRPC); + request.setType("gradle-project-kotlin"); + assertThat(gradleKotlinDslBuild(request)).hasPlugin("com.google.protobuf", "0.9.4") + .contains("import com.google.protobuf.gradle.id") + .containsIgnoringWhitespaces(""" + protobuf { + protoc { + artifact = "com.google.protobuf:protoc" + } + plugins { + id("grpc") { + artifact = "io.grpc:protoc-gen-grpc-java" + } + } + generateProtoTasks { + all().forEach { + it.plugins { + id("grpc") { + option("jakarta_omit") + } + } + } + } + } + """); + } + + @Test + void shouldAddOsPluginForMaven() { + ProjectRequest request = createProjectRequest(SPRING_GRPC); + assertThat(mavenPom(request)).containsIgnoringWhitespaces(""" + + kr.motd.maven + os-maven-plugin + 1.7.1 + + + initialize + initialize + + detect + + + + + """); + } + + @Test + void shouldAddProtobufPluginForMaven() { + ProjectRequest request = createProjectRequest(SPRING_GRPC); + assertThat(mavenPom(request)).hasProperty("grpc.version", "1.63.2") + .hasProperty("protobuf-java.version", "3.25.5") + .containsIgnoringWhitespaces( + """ + + org.xolstice.maven.plugins + protobuf-maven-plugin + 0.6.1 + + com.google.protobuf:protoc:${protobuf-java.version}:exe:${os.detected.classifier} + grpc-java + io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} + + + + compile + + compile + compile-custom + + + jakarta_omit + + + + + """); + } + + @Test + void shouldCreateSrcMainProtoDirectory() { + ProjectRequest request = createProjectRequest(SPRING_GRPC); + assertThat(generateProject(request)).containsDirectories("src/main/proto"); + } + +}