Skip to content

Commit 84aad66

Browse files
committed
Fix silent version fallback: error when requested JRE version not found
- Parse JBP_CONFIG_* version constraint and fail if version doesn't exist - Remove hardcoded Tomcat 9.0.98 fallback, return error instead - Convert Ruby buildpack '+' wildcard to '*' for libbuildpack semver - Add tests for JBP_CONFIG parsing and version-not-found error
1 parent 22f944a commit 84aad66

3 files changed

Lines changed: 61 additions & 16 deletions

File tree

src/java/containers/tomcat.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,7 @@ func (t *TomcatContainer) Supply() error {
9393
if dep.Version == "" {
9494
dep, err = t.context.Manifest.DefaultVersion("tomcat")
9595
if err != nil {
96-
t.context.Log.Warning("Unable to determine default Tomcat version")
97-
// Final fallback to a known version
98-
dep.Name = "tomcat"
99-
dep.Version = "9.0.98"
96+
return fmt.Errorf("failed to determine Tomcat version: no JAVA_HOME set and no default version in manifest: %w", err)
10097
}
10198
}
10299

src/java/jres/jre.go

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ package jres
22

33
import (
44
"fmt"
5-
"github.com/cloudfoundry/java-buildpack/src/java/common"
65
"os"
76
"path/filepath"
7+
"regexp"
88
"strings"
99

10+
"github.com/cloudfoundry/java-buildpack/src/java/common"
1011
"github.com/cloudfoundry/libbuildpack"
1112
)
1213

@@ -214,10 +215,23 @@ func GetJREVersion(ctx *common.Context, jreName string) (libbuildpack.Dependency
214215
// Check for legacy JBP_CONFIG_<JRE_NAME> environment variable
215216
envKey := fmt.Sprintf("JBP_CONFIG_%s", strings.ToUpper(strings.ReplaceAll(jreName, "-", "_")))
216217
if envVal := os.Getenv(envKey); envVal != "" {
217-
// Parse version from env (e.g., '{jre: {version: 11.+}}')
218-
// For now, simplified - just log it
219-
ctx.Log.Debug("JRE version override from %s: %s", envKey, envVal)
220-
// TODO: Parse YAML-like config from envVal
218+
versionPattern := parseJBPConfigVersion(envVal)
219+
if versionPattern == "" {
220+
return libbuildpack.Dependency{}, fmt.Errorf("could not parse version from %s='%s'", envKey, envVal)
221+
}
222+
223+
normalizedPattern := normalizeVersionPattern(versionPattern)
224+
availableVersions := ctx.Manifest.AllDependencyVersions(jreName)
225+
if len(availableVersions) == 0 {
226+
return libbuildpack.Dependency{}, fmt.Errorf("no versions of %s found in manifest", jreName)
227+
}
228+
229+
matchedVersion, err := libbuildpack.FindMatchingVersion(normalizedPattern, availableVersions)
230+
if err != nil {
231+
return libbuildpack.Dependency{}, fmt.Errorf("no version of %s matching '%s' found in manifest. Available versions: %v", jreName, versionPattern, availableVersions)
232+
}
233+
234+
return libbuildpack.Dependency{Name: jreName, Version: matchedVersion}, nil
221235
}
222236

223237
// Get default version from manifest (no version constraint)
@@ -229,18 +243,25 @@ func GetJREVersion(ctx *common.Context, jreName string) (libbuildpack.Dependency
229243
return dep, nil
230244
}
231245

232-
// normalizeVersionPattern converts user-friendly version strings to manifest patterns
233-
// Examples: "8" -> "8.*", "11" -> "11.*", "17.0" -> "17.0.*", "11.+" -> "11.+"
234246
func normalizeVersionPattern(version string) string {
235-
// If already has wildcard, return as-is
236-
if strings.Contains(version, "*") || strings.Contains(version, "+") {
247+
if strings.Contains(version, "+") {
248+
return strings.ReplaceAll(version, "+", "*")
249+
}
250+
if strings.Contains(version, "*") {
237251
return version
238252
}
239-
240-
// Otherwise append ".*" to match any patch version
241253
return version + ".*"
242254
}
243255

256+
func parseJBPConfigVersion(configValue string) string {
257+
re := regexp.MustCompile(`version:\s*['"]?([0-9]+[0-9.*+]*)['"]?`)
258+
matches := re.FindStringSubmatch(configValue)
259+
if len(matches) >= 2 {
260+
return strings.TrimSpace(matches[1])
261+
}
262+
return ""
263+
}
264+
244265
// WriteJavaOpts writes JAVA_OPTS to a .opts file for centralized assembly
245266
// JRE components use priority 05 to run early (before frameworks)
246267
func WriteJavaOpts(ctx *common.Context, opts string) error {

src/java/jres/jre_test.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,10 +268,37 @@ dependencies:
268268
dep, err := jres.GetJREVersion(ctx, "openjdk")
269269
Expect(err).NotTo(HaveOccurred())
270270
Expect(dep.Name).To(Equal("openjdk"))
271-
// Should match default version 17.x
272271
Expect(dep.Version).To(ContainSubstring("17."))
273272
})
274273
})
274+
275+
Context("with JBP_CONFIG_OPENJDK", func() {
276+
AfterEach(func() {
277+
os.Unsetenv("JBP_CONFIG_OPENJDK")
278+
})
279+
280+
It("resolves version from JBP_CONFIG", func() {
281+
os.Setenv("JBP_CONFIG_OPENJDK", "{jre: {version: 11.+}}")
282+
dep, err := jres.GetJREVersion(ctx, "openjdk")
283+
Expect(err).NotTo(HaveOccurred())
284+
Expect(dep.Name).To(Equal("openjdk"))
285+
Expect(dep.Version).To(Equal("11.0.25"))
286+
})
287+
288+
It("fails when requested version does not exist", func() {
289+
os.Setenv("JBP_CONFIG_OPENJDK", "{jre: {version: 99.+}}")
290+
_, err := jres.GetJREVersion(ctx, "openjdk")
291+
Expect(err).To(HaveOccurred())
292+
Expect(err.Error()).To(ContainSubstring("no version of openjdk matching"))
293+
})
294+
295+
It("fails when config format is invalid", func() {
296+
os.Setenv("JBP_CONFIG_OPENJDK", "invalid config")
297+
_, err := jres.GetJREVersion(ctx, "openjdk")
298+
Expect(err).To(HaveOccurred())
299+
Expect(err.Error()).To(ContainSubstring("could not parse version"))
300+
})
301+
})
275302
})
276303

277304
Describe("DetermineJavaVersion", func() {

0 commit comments

Comments
 (0)