diff --git a/src/integration/tomcat_test.go b/src/integration/tomcat_test.go index 841f01681..05c58d2d3 100644 --- a/src/integration/tomcat_test.go +++ b/src/integration/tomcat_test.go @@ -242,6 +242,27 @@ func testTomcat(platform switchblade.Platform, fixtures string) func(*testing.T, }) }) + // Regression test for https://github.com/cloudfoundry/java-buildpack/issues/1219 + // Staging failed with "improper constraint: 10.1.+" when using a two-segment + // minor version wildcard (e.g. 10.1.+) in JBP_CONFIG_TOMCAT. The fix normalises + // "10.1.+" → "10.1.*" before passing it to libbuildpack's FindMatchingVersion. + context("with a two-segment minor version wildcard in JBP_CONFIG_TOMCAT (issue #1219)", func() { + it("successfully stages with version: 10.1.+ and JBP_CONFIG_OPEN_JDK_JRE 17.+", func() { + deployment, logs, err := platform.Deploy. + WithEnv(map[string]string{ + "JBP_CONFIG_OPEN_JDK_JRE": "{ jre: { version: 17.+ } }", + "JBP_CONFIG_TOMCAT": "{tomcat: { version: 10.1.+ }}", + }). + Execute(name, filepath.Join(fixtures, "containers", "tomcat_jakarta")) + + Expect(err).NotTo(HaveOccurred(), logs.String) + + Expect(logs.String()).To(ContainSubstring("Installing OpenJDK 17.")) + Expect(logs.String()).To(ContainSubstring("Tomcat 10.1.")) + Eventually(deployment).Should(matchers.Serve(ContainSubstring("OK"))) + }) + }) + context("with memory limits", func() { it("respects memory calculator settings with JAVA_OPTS", func() { deployment, logs, err := platform.Deploy. diff --git a/src/java/containers/tomcat.go b/src/java/containers/tomcat.go index e7f078f98..c820fbd56 100644 --- a/src/java/containers/tomcat.go +++ b/src/java/containers/tomcat.go @@ -465,8 +465,9 @@ func DetermineTomcatVersion(raw string) string { // determineTomcatVersion determines the version of the tomcat // based on the JBP_CONFIG_TOMCAT field from manifest. -// It looks for a tomcat block with a version of the form ".+" (e.g. "9.+", "10.+"). -// Returns ".x" (e.g. "9.x", "10.x") so libbuildpack can resolve it, +// It looks for a tomcat block with a version of the form ".+" (e.g. "9.+", "10.+", "10.1.+"). +// Returns the pattern with "+" replaced by "*" (e.g. "9.*", "10.*", "10.1.*") so libbuildpack can resolve it. +// Masterminds/semver treats x, X, and * as equivalent wildcards. func determineTomcatVersion(raw string) string { raw = strings.TrimSpace(raw) if raw == "" { @@ -479,17 +480,9 @@ func determineTomcatVersion(raw string) string { return "" } - pattern := match[1] // e.g. "9.+", "10.+", "10.23.+" - - // If it's just ".+" (no additional dot), convert to ".x" - if !strings.Contains(strings.TrimSuffix(pattern, ".+"), ".") { - // "9.+" -> "9.x" - major := strings.TrimSuffix(pattern, ".+") - return major + ".x" - } - - // Otherwise, it's something like "10.23.+": pass it through unchanged - return pattern + // Replace "+" with "*" so libbuildpack's FindMatchingVersion can resolve it. + // e.g. "9.+" -> "9.*", "10.+" -> "10.*", "10.1.+" -> "10.1.*" + return strings.ReplaceAll(match[1], "+", "*") } // isAccessLoggingEnabled checks if access logging is enabled in configuration diff --git a/src/java/containers/tomcat_test.go b/src/java/containers/tomcat_test.go index 51e0c6718..bbd040dc9 100644 --- a/src/java/containers/tomcat_test.go +++ b/src/java/containers/tomcat_test.go @@ -203,22 +203,28 @@ var _ = Describe("Tomcat Container", func() { Expect(v).To(Equal("")) }) - It("returns 9.x for tomcat version 9.+", func() { + It("returns 9.* for tomcat version 9.+", func() { raw := `{ tomcat: { version: "9.+" } }` v := containers.DetermineTomcatVersion(raw) - Expect(v).To(Equal("9.x")) + Expect(v).To(Equal("9.*")) }) - It("returns 10.x for tomcat version 10.+", func() { + It("returns 10.* for tomcat version 10.+", func() { raw := `{ tomcat: { version: "10.+" } }` v := containers.DetermineTomcatVersion(raw) - Expect(v).To(Equal("10.x")) + Expect(v).To(Equal("10.*")) }) - It("returns 10.23.+ for tomcat version 10.23.+", func() { + It("returns 10.1.* for tomcat version 10.1.+", func() { + raw := `{tomcat: { version: 10.1.+, external_configuration_enabled: true }, external_configuration: { version: "1.4.0", repository_root: "https://example.com" }}` + v := containers.DetermineTomcatVersion(raw) + Expect(v).To(Equal("10.1.*")) + }) + + It("returns 10.23.* for tomcat version 10.23.+", func() { raw := `{ tomcat: { version: "10.23.+" } }` v := containers.DetermineTomcatVersion(raw) - Expect(v).To(Equal("10.23.+")) + Expect(v).To(Equal("10.23.*")) }) It("returns empty string when only access logging is configured", func() {