diff --git a/src/java/frameworks/java_cf_env.go b/src/java/frameworks/java_cf_env.go index f1a0294ef..a6438153e 100644 --- a/src/java/frameworks/java_cf_env.go +++ b/src/java/frameworks/java_cf_env.go @@ -2,11 +2,12 @@ package frameworks import ( "fmt" - "github.com/cloudfoundry/java-buildpack/src/java/common" "os" "path/filepath" "strings" + "github.com/cloudfoundry/java-buildpack/src/java/common" + "github.com/cloudfoundry/libbuildpack" "gopkg.in/yaml.v2" ) @@ -31,8 +32,8 @@ func (j *JavaCfEnvFramework) Detect() (string, error) { return "", nil } - // Check if Spring Boot 3.x is present - if !j.isSpringBoot3() { + // Check if Spring Boot 3.x/4.x is present + if !j.isSpringBootMajor(4) && !j.isSpringBootMajor(3) { return "", nil } @@ -49,14 +50,27 @@ func (j *JavaCfEnvFramework) Detect() (string, error) { func (j *JavaCfEnvFramework) Supply() error { j.context.Log.BeginStep("Installing Java CF Env") - // Get java-cfenv dependency from manifest - dep, err := j.context.Manifest.DefaultVersion("java-cfenv") + dependency := "java-cfenv" + defaultVersion := "4.0.0" + versionPattern := "4.x.x" + + if j.isSpringBootMajor(3) { + defaultVersion = "3.1.0" + versionPattern = "3.x.x" + } + + allVersions := j.context.Manifest.AllDependencyVersions(dependency) + resolvedVersion, err := libbuildpack.FindMatchingVersion(versionPattern, allVersions) + + dep := libbuildpack.Dependency{Name: dependency, Version: resolvedVersion} if err != nil { - j.context.Log.Warning("Unable to determine Java CF Env version, using default") + j.context.Log.Warning("Unable to determine Java CF Env version for pattern %s, using default", versionPattern) dep = libbuildpack.Dependency{ - Name: "java-cfenv", - Version: "3.1.0", // Fallback version + Name: dependency, + Version: defaultVersion, } + } else { + j.context.Log.Debug("Resolved Java CF Env version pattern '%s' to %s", versionPattern, resolvedVersion) } // Install java-cfenv JAR @@ -139,15 +153,14 @@ func (j *JavaCfEnvFramework) isEnabled() bool { return true } -// isSpringBoot3 checks if the application is Spring Boot 3.x -func (j *JavaCfEnvFramework) isSpringBoot3() bool { - // Look for Spring Boot 3.x JARs - // Spring Boot 3.x uses spring-boot-3.*.jar +// isSpringBootMajor checks if the application is Spring Boot .x +func (j *JavaCfEnvFramework) isSpringBootMajor(major int) bool { + jarGlob := fmt.Sprintf("spring-boot-%d.*.jar", major) patterns := []string{ - filepath.Join(j.context.Stager.BuildDir(), "**", "spring-boot-3.*.jar"), - filepath.Join(j.context.Stager.BuildDir(), "WEB-INF", "lib", "spring-boot-3.*.jar"), - filepath.Join(j.context.Stager.BuildDir(), "BOOT-INF", "lib", "spring-boot-3.*.jar"), - filepath.Join(j.context.Stager.BuildDir(), "lib", "spring-boot-3.*.jar"), + filepath.Join(j.context.Stager.BuildDir(), "**", jarGlob), + filepath.Join(j.context.Stager.BuildDir(), "WEB-INF", "lib", jarGlob), + filepath.Join(j.context.Stager.BuildDir(), "BOOT-INF", "lib", jarGlob), + filepath.Join(j.context.Stager.BuildDir(), "lib", jarGlob), } for _, pattern := range patterns { @@ -161,7 +174,7 @@ func (j *JavaCfEnvFramework) isSpringBoot3() bool { manifestPath := filepath.Join(j.context.Stager.BuildDir(), "META-INF", "MANIFEST.MF") if content, err := os.ReadFile(manifestPath); err == nil { manifest := string(content) - if strings.Contains(manifest, "Spring-Boot-Version: 3.") { + if strings.Contains(manifest, fmt.Sprintf("Spring-Boot-Version: %d.", major)) { return true } } diff --git a/src/java/supply/supply_test.go b/src/java/supply/supply_test.go index 18a6086e2..ad66dc28c 100644 --- a/src/java/supply/supply_test.go +++ b/src/java/supply/supply_test.go @@ -1,12 +1,13 @@ package supply_test import ( - "github.com/cloudfoundry/java-buildpack/src/internal/mocks" - "github.com/golang/mock/gomock" "os" "path/filepath" "time" + "github.com/cloudfoundry/java-buildpack/src/internal/mocks" + "github.com/golang/mock/gomock" + "github.com/cloudfoundry/java-buildpack/src/java/supply" "github.com/cloudfoundry/libbuildpack" . "github.com/onsi/ginkgo/v2" @@ -177,7 +178,32 @@ dependencies: [] }) }) - Context("When a Spring-boot application is present", func() { + Context("When a Spring-boot 4 application is present", func() { + BeforeEach(func() { + // Create a Spring Boot JAR with BOOT-INF + bootInfDir := filepath.Join(buildDir, "BOOT-INF") + Expect(os.MkdirAll(bootInfDir, 0755)).To(Succeed()) + Expect(os.MkdirAll(filepath.Join(buildDir, "META-INF"), 0755)).To(Succeed()) + + // Create META-INF/MANIFEST.MF with corresponding content of a Spring Boot app + manifestFile := filepath.Join(buildDir, "META-INF", "MANIFEST.MF") + Expect(os.WriteFile(manifestFile, []byte("Spring-Boot-Version: 4.x.x"), 0644)).To(Succeed()) + + //Create install dir and mock for the java cf env spring boot related dependency + javaCfEnvInstallDir := filepath.Join(depsDir, depsIdx, "java_cf_env") + Expect(os.MkdirAll(filepath.Join(javaCfEnvInstallDir), 0755)).To(Succeed()) + + depJavaCfEnv := libbuildpack.Dependency{Name: "java-cfenv", Version: "4.999.0"} + mockManifest.EXPECT().AllDependencyVersions("java-cfenv").Return([]string{"4.999.0", "3.999.0"}) + mockInstaller.EXPECT().InstallDependency(depJavaCfEnv, javaCfEnvInstallDir).Return(nil) + }) + + It("Supply passes successfully", func() { + Expect(supply.Run(supplier)).To(Succeed()) + }) + }) + + Context("When a Spring-boot 3 application is present", func() { BeforeEach(func() { // Create a Spring Boot JAR with BOOT-INF bootInfDir := filepath.Join(buildDir, "BOOT-INF") @@ -192,8 +218,8 @@ dependencies: [] javaCfEnvInstallDir := filepath.Join(depsDir, depsIdx, "java_cf_env") Expect(os.MkdirAll(filepath.Join(javaCfEnvInstallDir), 0755)).To(Succeed()) - depJavaCfEnv := libbuildpack.Dependency{Name: "java-cfenv", Version: "3.5.0"} - mockManifest.EXPECT().DefaultVersion("java-cfenv").Return(depJavaCfEnv, nil) + depJavaCfEnv := libbuildpack.Dependency{Name: "java-cfenv", Version: "3.999.0"} + mockManifest.EXPECT().AllDependencyVersions("java-cfenv").Return([]string{"4.999.0", "3.999.0"}) mockInstaller.EXPECT().InstallDependency(depJavaCfEnv, javaCfEnvInstallDir).Return(nil) })