Skip to content

Commit 8eb9829

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 961ffe0 commit 8eb9829

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
@@ -76,6 +76,8 @@ it. Gradle runs the two in parallel.
7676
module once it's added to its workflow.
7777
- Suite code may only use APIs that exist in the oldest version of its line. Compiled against a
7878
newer one, a missing API fails at runtime with `NoSuchMethodError` or `NoClassDefFoundError`.
79+
- The oldest version's aggregate also compiles the module's main code against that version, e.g.
80+
`compileJavaBoot3_2_12`, since nothing else checks that the SDK compiles against it.
7981

8082
## Gotchas
8183

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

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

@@ -30,6 +31,10 @@ abstract class SpringBootMatrixExtension @Inject constructor(private val project
3031
* `gradle/spring-boot-versions.json`, and `allIntegrationTestsBoot<line>` for all of them. The CI
3132
* workflows read the same file and run each version in its own job. A WAR module uses its Boot
3233
* module's line, because the Boot BOM decides its Spring version.
34+
*
35+
* The line's first version must be the oldest. The module's main code compiles against it in
36+
* `compileJavaBoot<version>`, part of that version's aggregate, because the main compilation only
37+
* proves the code compiles against the catalog's version.
3338
*/
3439
fun versions(line: Int) {
3540
val file = project.layout.settingsDirectory.file("gradle/spring-boot-versions.json")
@@ -48,6 +53,22 @@ abstract class SpringBootMatrixExtension @Inject constructor(private val project
4853
group = LifecycleBasePlugin.VERIFICATION_GROUP
4954
}
5055
}
56+
57+
val oldest = versions.first()
58+
val compileClasspath = classpath("main", oldest, compile = true)
59+
val compileOldest =
60+
project.tasks.register("compileJava${suffix(oldest)}", JavaCompile::class.java) {
61+
description = "Compiles the main Java sources against Spring Boot $oldest."
62+
group = LifecycleBasePlugin.VERIFICATION_GROUP
63+
val compileJava = project.tasks.named("compileJava", JavaCompile::class.java).get()
64+
source = sourceSet("main").java
65+
classpath = compileClasspath
66+
destinationDirectory.set(project.layout.buildDirectory.dir("classes/java/main${suffix(oldest)}"))
67+
javaCompiler.set(compileJava.javaCompiler)
68+
options.release.set(compileJava.options.release)
69+
options.annotationProcessorPath = compileJava.options.annotationProcessorPath
70+
}
71+
project.tasks.named(aggregateName(oldest)) { dependsOn(compileOldest) }
5172
}
5273

5374
/**
@@ -74,28 +95,29 @@ abstract class SpringBootMatrixExtension @Inject constructor(private val project
7495
}
7596

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

101123
private fun sourceSet(name: String) =

0 commit comments

Comments
 (0)