Skip to content

Commit 25c20ff

Browse files
runningcodeclaude
andcommitted
test(spring): Compile the Spring modules against their oldest Spring Boot version
Since the matrix stopped rewriting the catalog, the SDK only compiles against the catalog's Spring Boot version, so nothing checked any more that it compiles against the oldest version of each line. An unguarded call to a newer API would only fail if a suite ran that code path. The Spring Boot matrix plugin now registers compileJavaBoot<oldest> in each of the six modules, compiling the main sources against a compile classpath resolved for the line's oldest version. The oldest version's aggregate depends on it, so the matrix workflows run it. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 8d9fab1 commit 25c20ff

2 files changed

Lines changed: 43 additions & 19 deletions

File tree

‎.cursor/rules/e2e_tests.mdc‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ it. Gradle runs the two in parallel.
7474
runs on CI once it's added to its module's `springBootMatrix` block.
7575
- Suite code may only use APIs that exist in the oldest version of its line. Compiled against a
7676
newer one, a missing API fails at runtime with `NoSuchMethodError` or `NoClassDefFoundError`.
77+
- The oldest version's aggregate also compiles the module's main code against that version, e.g.
78+
`compileJavaBoot3_2_12`, since nothing else checks that the SDK compiles against it.
7779

7880
## Gotchas
7981

‎build-logic/src/main/kotlin/io/sentry/gradle/SpringBootMatrixPlugin.kt‎

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import org.gradle.api.Plugin
55
import org.gradle.api.Project
66
import org.gradle.api.file.FileCollection
77
import org.gradle.api.tasks.SourceSetContainer
8+
import org.gradle.api.tasks.compile.JavaCompile
89
import org.gradle.api.tasks.testing.Test
910
import org.gradle.language.base.plugins.LifecycleBasePlugin
1011

@@ -28,6 +29,10 @@ abstract class SpringBootMatrixExtension @Inject constructor(private val project
2829
* Registers `allIntegrationTestsBoot<version>` for each of [versions], and
2930
* `allIntegrationTestsBoot<major>` for all of them, which CI runs from the root project for every
3031
* module of the line at once.
32+
*
33+
* The first of [versions] must be the oldest. The module's main code compiles against it in
34+
* `compileJavaBoot<version>`, part of that version's aggregate, because the main compilation only
35+
* proves the code compiles against the catalog's version.
3136
*/
3237
fun versions(versions: List<String>) {
3338
this.versions = versions
@@ -43,6 +48,22 @@ abstract class SpringBootMatrixExtension @Inject constructor(private val project
4348
group = LifecycleBasePlugin.VERIFICATION_GROUP
4449
}
4550
}
51+
52+
val oldest = versions.first()
53+
val compileClasspath = classpath("main", oldest, compile = true)
54+
val compileOldest =
55+
project.tasks.register("compileJava${suffix(oldest)}", JavaCompile::class.java) {
56+
description = "Compiles the main Java sources against Spring Boot $oldest."
57+
group = LifecycleBasePlugin.VERIFICATION_GROUP
58+
val compileJava = project.tasks.named("compileJava", JavaCompile::class.java).get()
59+
source = sourceSet("main").java
60+
classpath = compileClasspath
61+
destinationDirectory.set(project.layout.buildDirectory.dir("classes/java/main${suffix(oldest)}"))
62+
javaCompiler.set(compileJava.javaCompiler)
63+
options.release.set(compileJava.options.release)
64+
options.annotationProcessorPath = compileJava.options.annotationProcessorPath
65+
}
66+
project.tasks.named(aggregateName(oldest)) { dependsOn(compileOldest) }
4667
}
4768

4869
/**
@@ -69,28 +90,29 @@ abstract class SpringBootMatrixExtension @Inject constructor(private val project
6990
}
7091

7192
/** [sourceSet]'s output and runtime dependencies, with Spring Boot at [version]. */
72-
fun runtimeClasspath(sourceSet: String, version: String): FileCollection {
93+
fun runtimeClasspath(sourceSet: String, version: String): FileCollection =
94+
sourceSet(sourceSet).output + classpath(sourceSet, version, compile = false)
95+
96+
/** [sourceSet]'s compile or runtime classpath dependencies, with Spring Boot at [version]. */
97+
private fun classpath(sourceSet: String, version: String, compile: Boolean): FileCollection {
7398
val sources = sourceSet(sourceSet)
74-
val name = "$sourceSet${suffix(version)}RuntimeClasspath"
99+
val base =
100+
if (compile) sources.compileClasspathConfigurationName
101+
else sources.runtimeClasspathConfigurationName
102+
val name = "$sourceSet${suffix(version)}${if (compile) "Compile" else "Runtime"}Classpath"
75103
val configurations = project.configurations
76-
val dependencies =
77-
configurations.findByName(name)
78-
?: configurations.create(name) {
79-
isCanBeConsumed = false
80-
extendsFrom(
81-
configurations.getByName(sources.implementationConfigurationName),
82-
configurations.getByName(sources.runtimeOnlyConfigurationName),
83-
)
84-
attributes.addAllLater(
85-
configurations.getByName(sources.runtimeClasspathConfigurationName).attributes
86-
)
87-
// What setting the version in the catalog does: every Spring Boot artifact, the BOM
88-
// included, is in this group. Libraries pinned to their own version still win conflicts.
89-
resolutionStrategy.eachDependency {
90-
if (requested.group == "org.springframework.boot") useVersion(version)
91-
}
104+
return configurations.findByName(name)
105+
?: configurations.create(name) {
106+
isCanBeConsumed = false
107+
val baseConfiguration = configurations.getByName(base)
108+
extendsFrom(*baseConfiguration.extendsFrom.toTypedArray())
109+
attributes.addAllLater(baseConfiguration.attributes)
110+
// What setting the version in the catalog does: every Spring Boot artifact, the BOM
111+
// included, is in this group. Libraries pinned to their own version still win conflicts.
112+
resolutionStrategy.eachDependency {
113+
if (requested.group == "org.springframework.boot") useVersion(version)
92114
}
93-
return sources.output + dependencies
115+
}
94116
}
95117

96118
private fun sourceSet(name: String) =

0 commit comments

Comments
 (0)