Skip to content

Commit f114449

Browse files
committed
Polish "Generate test apps for spring-ai projects"
See gh-1484
1 parent 25f4998 commit f114449

15 files changed

+260
-156
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.spring.start.site.extension.dependency.springai;
18+
19+
import java.lang.annotation.Documented;
20+
import java.lang.annotation.ElementType;
21+
import java.lang.annotation.Retention;
22+
import java.lang.annotation.RetentionPolicy;
23+
import java.lang.annotation.Target;
24+
25+
import io.spring.initializr.generator.project.ProjectDescription;
26+
27+
import org.springframework.context.annotation.Conditional;
28+
29+
/**
30+
* Condition that matches when a {@link ProjectDescription} defines a dependency on Spring
31+
* AI. A generated project may ultimately define a different set of dependencies according
32+
* to the contributors that have been executed. To contribute to the project according to
33+
* the real set, prefer querying the model itself rather than using this condition.
34+
*
35+
* @author Moritz Halbritter
36+
*/
37+
@Retention(RetentionPolicy.RUNTIME)
38+
@Target({ ElementType.TYPE, ElementType.METHOD })
39+
@Documented
40+
@Conditional(OnRequestedSpringAiDependencyCondition.class)
41+
@interface ConditionalOnRequestedSpringAiDependency {
42+
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.spring.start.site.extension.dependency.springai;
18+
19+
import io.spring.initializr.generator.buildsystem.Dependency;
20+
import io.spring.initializr.generator.condition.ProjectGenerationCondition;
21+
import io.spring.initializr.generator.project.ProjectDescription;
22+
23+
import org.springframework.context.annotation.ConditionContext;
24+
import org.springframework.core.type.AnnotatedTypeMetadata;
25+
26+
/**
27+
* {@link ProjectGenerationCondition} implementation for
28+
* {@link ConditionalOnRequestedSpringAiDependency}.
29+
*
30+
* @author Moritz Halbritter
31+
*/
32+
class OnRequestedSpringAiDependencyCondition extends ProjectGenerationCondition {
33+
34+
@Override
35+
protected boolean matches(ProjectDescription description, ConditionContext context,
36+
AnnotatedTypeMetadata metadata) {
37+
for (Dependency dependency : description.getRequestedDependencies().values()) {
38+
if (dependency.getGroupId().equals("org.springframework.ai")) {
39+
return true;
40+
}
41+
}
42+
return false;
43+
}
44+
45+
}

start-site/src/main/java/io/spring/start/site/extension/dependency/springai/SpringAiChromaProjectGenerationConfiguration.java

+6-17
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@
1717
package io.spring.start.site.extension.dependency.springai;
1818

1919
import io.spring.initializr.generator.condition.ConditionalOnRequestedDependency;
20-
import io.spring.initializr.generator.project.ProjectDescription;
2120
import io.spring.initializr.generator.project.ProjectGenerationConfiguration;
22-
import io.spring.initializr.metadata.InitializrMetadata;
2321
import io.spring.start.site.container.ComposeFileCustomizer;
2422
import io.spring.start.site.container.DockerServiceResolver;
2523
import io.spring.start.site.container.ServiceConnections.ServiceConnection;
@@ -40,25 +38,16 @@ class SpringAiChromaProjectGenerationConfiguration {
4038

4139
@Bean
4240
@ConditionalOnRequestedDependency("testcontainers")
43-
ServiceConnectionsCustomizer chromaServiceConnectionsCustomizer(InitializrMetadata metadata,
44-
ProjectDescription description, DockerServiceResolver serviceResolver) {
45-
return (serviceConnections) -> {
46-
if (SpringAiVersion.version1OrLater(metadata, description.getPlatformVersion())) {
47-
serviceResolver.doWith("chroma", (service) -> serviceConnections
48-
.addServiceConnection(ServiceConnection.ofContainer("chroma", service, TESTCONTAINERS_CLASS_NAME)));
49-
}
50-
};
41+
ServiceConnectionsCustomizer chromaServiceConnectionsCustomizer(DockerServiceResolver serviceResolver) {
42+
return (serviceConnections) -> serviceResolver.doWith("chroma", (service) -> serviceConnections
43+
.addServiceConnection(ServiceConnection.ofContainer("chroma", service, TESTCONTAINERS_CLASS_NAME, false)));
5144
}
5245

5346
@Bean
5447
@ConditionalOnRequestedDependency("docker-compose")
55-
ComposeFileCustomizer chromaComposeFileCustomizer(InitializrMetadata metadata, ProjectDescription description,
56-
DockerServiceResolver serviceResolver) {
57-
return (composeFile) -> {
58-
if (SpringAiVersion.version1OrLater(metadata, description.getPlatformVersion())) {
59-
serviceResolver.doWith("chroma", (service) -> composeFile.services().add("chroma", service));
60-
}
61-
};
48+
ComposeFileCustomizer chromaComposeFileCustomizer(DockerServiceResolver serviceResolver) {
49+
return (composeFile) -> serviceResolver.doWith("chroma",
50+
(service) -> composeFile.services().add("chroma", service));
6251
}
6352

6453
}

start-site/src/main/java/io/spring/start/site/extension/dependency/springai/SpringAiDockerComposeProjectGenerationConfiguration.java

+22-9
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import io.spring.initializr.generator.project.ProjectDescription;
2424
import io.spring.initializr.generator.project.ProjectGenerationConfiguration;
2525
import io.spring.initializr.generator.spring.build.BuildCustomizer;
26+
import io.spring.initializr.generator.version.VersionProperty;
27+
import io.spring.initializr.generator.version.VersionReference;
2628
import io.spring.initializr.metadata.InitializrMetadata;
2729

2830
import org.springframework.context.annotation.Bean;
@@ -34,19 +36,30 @@
3436
*/
3537
@ProjectGenerationConfiguration
3638
@ConditionalOnRequestedDependency("docker-compose")
37-
class SpringAiDockerComposeProjectGenerationConfiguration {
39+
@ConditionalOnRequestedSpringAiDependency
40+
public class SpringAiDockerComposeProjectGenerationConfiguration {
41+
42+
/**
43+
* Dependency id of
44+
* {@code org.springframework.ai:spring-ai-spring-boot-docker-compose}.
45+
*/
46+
public static final String DEPENDENCY_ID = "spring-ai-docker-compose";
3847

3948
@Bean
4049
BuildCustomizer<Build> springAiDockerComposeBuildCustomizer(InitializrMetadata metadata,
4150
ProjectDescription description) {
42-
return (build) -> {
43-
if (SpringAiVersion.version1OrLater(metadata, description.getPlatformVersion())) {
44-
build.dependencies()
45-
.add("spring-ai-docker-compose",
46-
Dependency.withCoordinates("org.springframework.ai", "spring-ai-spring-boot-docker-compose")
47-
.scope(DependencyScope.TEST_COMPILE));
48-
}
49-
};
51+
// spring-ai-spring-boot-docker-compose is not managed in the BOM
52+
// See https://github.com/spring-projects/spring-ai/issues/1314
53+
VersionProperty springAiBomVersion = getSpringAiVersion(metadata, description);
54+
return (build) -> build.dependencies()
55+
.add(DEPENDENCY_ID,
56+
Dependency.withCoordinates("org.springframework.ai", "spring-ai-spring-boot-docker-compose")
57+
.version(VersionReference.ofProperty(springAiBomVersion))
58+
.scope(DependencyScope.RUNTIME));
59+
}
60+
61+
private static VersionProperty getSpringAiVersion(InitializrMetadata metadata, ProjectDescription description) {
62+
return metadata.getConfiguration().getEnv().getBoms().get("spring-ai").getVersionProperty();
5063
}
5164

5265
}

start-site/src/main/java/io/spring/start/site/extension/dependency/springai/SpringAiMilvusProjectGenerationConfiguration.java

+3-10
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@
1717
package io.spring.start.site.extension.dependency.springai;
1818

1919
import io.spring.initializr.generator.condition.ConditionalOnRequestedDependency;
20-
import io.spring.initializr.generator.project.ProjectDescription;
2120
import io.spring.initializr.generator.project.ProjectGenerationConfiguration;
22-
import io.spring.initializr.metadata.InitializrMetadata;
2321
import io.spring.start.site.container.DockerServiceResolver;
2422
import io.spring.start.site.container.ServiceConnections.ServiceConnection;
2523
import io.spring.start.site.container.ServiceConnectionsCustomizer;
@@ -39,14 +37,9 @@ class SpringAiMilvusProjectGenerationConfiguration {
3937

4038
@Bean
4139
@ConditionalOnRequestedDependency("testcontainers")
42-
ServiceConnectionsCustomizer milvusServiceConnectionsCustomizer(InitializrMetadata metadata,
43-
ProjectDescription description, DockerServiceResolver serviceResolver) {
44-
return (serviceConnections) -> {
45-
if (SpringAiVersion.version1OrLater(metadata, description.getPlatformVersion())) {
46-
serviceResolver.doWith("milvus", (service) -> serviceConnections
47-
.addServiceConnection(ServiceConnection.ofContainer("milvus", service, TESTCONTAINERS_CLASS_NAME)));
48-
}
49-
};
40+
ServiceConnectionsCustomizer milvusServiceConnectionsCustomizer(DockerServiceResolver serviceResolver) {
41+
return (serviceConnections) -> serviceResolver.doWith("milvus", (service) -> serviceConnections
42+
.addServiceConnection(ServiceConnection.ofContainer("milvus", service, TESTCONTAINERS_CLASS_NAME, false)));
5043
}
5144

5245
}

start-site/src/main/java/io/spring/start/site/extension/dependency/springai/SpringAiOllamaProjectGenerationConfiguration.java

+6-17
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@
1717
package io.spring.start.site.extension.dependency.springai;
1818

1919
import io.spring.initializr.generator.condition.ConditionalOnRequestedDependency;
20-
import io.spring.initializr.generator.project.ProjectDescription;
2120
import io.spring.initializr.generator.project.ProjectGenerationConfiguration;
22-
import io.spring.initializr.metadata.InitializrMetadata;
2321
import io.spring.start.site.container.ComposeFileCustomizer;
2422
import io.spring.start.site.container.DockerServiceResolver;
2523
import io.spring.start.site.container.ServiceConnections.ServiceConnection;
@@ -40,25 +38,16 @@ class SpringAiOllamaProjectGenerationConfiguration {
4038

4139
@Bean
4240
@ConditionalOnRequestedDependency("testcontainers")
43-
ServiceConnectionsCustomizer ollamaServiceConnectionsCustomizer(InitializrMetadata metadata,
44-
ProjectDescription description, DockerServiceResolver serviceResolver) {
45-
return (serviceConnections) -> {
46-
if (SpringAiVersion.version1OrLater(metadata, description.getPlatformVersion())) {
47-
serviceResolver.doWith("ollama", (service) -> serviceConnections
48-
.addServiceConnection(ServiceConnection.ofContainer("ollama", service, TESTCONTAINERS_CLASS_NAME)));
49-
}
50-
};
41+
ServiceConnectionsCustomizer ollamaServiceConnectionsCustomizer(DockerServiceResolver serviceResolver) {
42+
return (serviceConnections) -> serviceResolver.doWith("ollama", (service) -> serviceConnections
43+
.addServiceConnection(ServiceConnection.ofContainer("ollama", service, TESTCONTAINERS_CLASS_NAME, false)));
5144
}
5245

5346
@Bean
5447
@ConditionalOnRequestedDependency("docker-compose")
55-
ComposeFileCustomizer ollamaComposeFileCustomizer(InitializrMetadata metadata, ProjectDescription description,
56-
DockerServiceResolver serviceResolver) {
57-
return (composeFile) -> {
58-
if (SpringAiVersion.version1OrLater(metadata, description.getPlatformVersion())) {
59-
serviceResolver.doWith("ollama", (service) -> composeFile.services().add("ollama", service));
60-
}
61-
};
48+
ComposeFileCustomizer ollamaComposeFileCustomizer(DockerServiceResolver serviceResolver) {
49+
return (composeFile) -> serviceResolver.doWith("ollama",
50+
(service) -> composeFile.services().add("ollama", service));
6251
}
6352

6453
}

start-site/src/main/java/io/spring/start/site/extension/dependency/springai/SpringAiQdrantProjectGenerationConfiguration.java

+6-17
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@
1717
package io.spring.start.site.extension.dependency.springai;
1818

1919
import io.spring.initializr.generator.condition.ConditionalOnRequestedDependency;
20-
import io.spring.initializr.generator.project.ProjectDescription;
2120
import io.spring.initializr.generator.project.ProjectGenerationConfiguration;
22-
import io.spring.initializr.metadata.InitializrMetadata;
2321
import io.spring.start.site.container.ComposeFileCustomizer;
2422
import io.spring.start.site.container.DockerServiceResolver;
2523
import io.spring.start.site.container.ServiceConnections.ServiceConnection;
@@ -40,25 +38,16 @@ class SpringAiQdrantProjectGenerationConfiguration {
4038

4139
@Bean
4240
@ConditionalOnRequestedDependency("testcontainers")
43-
ServiceConnectionsCustomizer qdrantServiceConnectionsCustomizer(InitializrMetadata metadata,
44-
ProjectDescription description, DockerServiceResolver serviceResolver) {
45-
return (serviceConnections) -> {
46-
if (SpringAiVersion.version1OrLater(metadata, description.getPlatformVersion())) {
47-
serviceResolver.doWith("qdrant", (service) -> serviceConnections
48-
.addServiceConnection(ServiceConnection.ofContainer("qdrant", service, TESTCONTAINERS_CLASS_NAME)));
49-
}
50-
};
41+
ServiceConnectionsCustomizer qdrantServiceConnectionsCustomizer(DockerServiceResolver serviceResolver) {
42+
return (serviceConnections) -> serviceResolver.doWith("qdrant", (service) -> serviceConnections
43+
.addServiceConnection(ServiceConnection.ofContainer("qdrant", service, TESTCONTAINERS_CLASS_NAME, false)));
5144
}
5245

5346
@Bean
5447
@ConditionalOnRequestedDependency("docker-compose")
55-
ComposeFileCustomizer qdrantComposeFileCustomizer(InitializrMetadata metadata, ProjectDescription description,
56-
DockerServiceResolver serviceResolver) {
57-
return (composeFile) -> {
58-
if (SpringAiVersion.version1OrLater(metadata, description.getPlatformVersion())) {
59-
serviceResolver.doWith("qdrant", (service) -> composeFile.services().add("qdrant", service));
60-
}
61-
};
48+
ComposeFileCustomizer qdrantComposeFileCustomizer(DockerServiceResolver serviceResolver) {
49+
return (composeFile) -> serviceResolver.doWith("qdrant",
50+
(service) -> composeFile.services().add("qdrant", service));
6251
}
6352

6453
}

start-site/src/main/java/io/spring/start/site/extension/dependency/springai/SpringAiTestcontainersProjectGenerationConfiguration.java

+6-12
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@
2020
import io.spring.initializr.generator.buildsystem.Dependency;
2121
import io.spring.initializr.generator.buildsystem.DependencyScope;
2222
import io.spring.initializr.generator.condition.ConditionalOnRequestedDependency;
23-
import io.spring.initializr.generator.project.ProjectDescription;
2423
import io.spring.initializr.generator.project.ProjectGenerationConfiguration;
2524
import io.spring.initializr.generator.spring.build.BuildCustomizer;
26-
import io.spring.initializr.metadata.InitializrMetadata;
2725

2826
import org.springframework.context.annotation.Bean;
2927

@@ -34,19 +32,15 @@
3432
*/
3533
@ProjectGenerationConfiguration
3634
@ConditionalOnRequestedDependency("testcontainers")
35+
@ConditionalOnRequestedSpringAiDependency
3736
class SpringAiTestcontainersProjectGenerationConfiguration {
3837

3938
@Bean
40-
BuildCustomizer<Build> springAiTestcontainersBuildCustomizer(InitializrMetadata metadata,
41-
ProjectDescription description) {
42-
return (build) -> {
43-
if (SpringAiVersion.version1OrLater(metadata, description.getPlatformVersion())) {
44-
build.dependencies()
45-
.add("spring-ai-testcontainers",
46-
Dependency.withCoordinates("org.springframework.ai", "spring-ai-spring-boot-testcontainers")
47-
.scope(DependencyScope.TEST_COMPILE));
48-
}
49-
};
39+
BuildCustomizer<Build> springAiTestcontainersBuildCustomizer() {
40+
return (build) -> build.dependencies()
41+
.add("spring-ai-testcontainers",
42+
Dependency.withCoordinates("org.springframework.ai", "spring-ai-spring-boot-testcontainers")
43+
.scope(DependencyScope.TEST_COMPILE));
5044
}
5145

5246
}

start-site/src/main/java/io/spring/start/site/extension/dependency/springai/SpringAiVersion.java

-42
This file was deleted.

0 commit comments

Comments
 (0)