Skip to content

Commit 779268b

Browse files
committed
Refactor release phase to use YAML pattern instead of bash wrapper
**Problem:** The Java buildpack was using a custom bash wrapper script ($HOME/.java-buildpack/start.sh) that sourced profile.d scripts and executed the container command. This pattern: - Required maintaining custom bash logic for environment setup - Didn't follow Cloud Foundry buildpack conventions - Made it harder to integrate with CF lifecycle hooks **Solution:** Adopt the standard release YAML pattern used by all reference buildpacks (Ruby, Go, Node.js, Python): 1. **Finalize phase** writes `tmp/java-buildpack-release-step.yml` with direct container commands (e.g., `bin/application` for DistZip, `java -jar app.jar` for Spring Boot) 2. **Release phase** reads and outputs this YAML to stdout for Cloud Foundry to parse 3. **Cloud Foundry runtime** handles profile.d sourcing automatically before executing the command **Changes:** - src/java/finalize/cli/main.go: Added RunAfterCompile() and SetLaunchEnvironment() lifecycle hooks - src/java/finalize/finalize.go: Replaced generateStartupScript() with writeReleaseYaml() - src/java/release/release.go: Changed from hardcoded bash wrapper to YAML passthrough - src/java/release/release_test.go: Updated test to simulate finalize phase creating YAML file **Benefits:** - Aligns with Cloud Foundry buildpack conventions - Simplifies maintenance (no custom bash wrapper logic) - Better integration with CF lifecycle hooks - Profile.d scripts handled by platform (from Commit 1: 23bd35c) **Related:** - Depends on Commit 1 (23bd35c) which migrated environment setup to .profile.d/*.sh scripts - Part of 3-commit refactoring series to align with CF runtime standards
1 parent 041d773 commit 779268b

File tree

4 files changed

+65
-50
lines changed

4 files changed

+65
-50
lines changed

src/java/finalize/cli/main.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,16 @@ func main() {
6262
os.Exit(14)
6363
}
6464

65+
if err := libbuildpack.RunAfterCompile(stager); err != nil {
66+
logger.Error("After Compile: %s", err.Error())
67+
os.Exit(13)
68+
}
69+
70+
if err := stager.SetLaunchEnvironment(); err != nil {
71+
logger.Error("Unable to setup launch environment: %s", err.Error())
72+
os.Exit(16)
73+
}
74+
6575
if err := stager.WriteConfigYml(nil); err != nil {
6676
logger.Error("Error writing config.yml: %s", err.Error())
6777
os.Exit(15)

src/java/finalize/finalize.go

Lines changed: 22 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ func Run(f *Finalizer) error {
7474
return err
7575
}
7676

77-
// Generate startup script
78-
if err := f.generateStartupScript(container); err != nil {
79-
f.Log.Error("Failed to generate startup script: %s", err.Error())
77+
// Write release YAML configuration
78+
if err := f.writeReleaseYaml(container); err != nil {
79+
f.Log.Error("Failed to write release YAML: %s", err.Error())
8080
return err
8181
}
8282

@@ -224,56 +224,35 @@ func (f *Finalizer) finalizeFrameworks() error {
224224
return nil
225225
}
226226

227-
// generateStartupScript creates the main startup script that Cloud Foundry will execute
228-
func (f *Finalizer) generateStartupScript(container containers.Container) error {
229-
f.Log.BeginStep("Generating startup script")
230-
231-
// Create .java-buildpack directory in HOME
232-
// In Cloud Foundry, $HOME is the app directory at runtime
233-
javaBuildpackDir := filepath.Join(f.Stager.BuildDir(), ".java-buildpack")
234-
if err := os.MkdirAll(javaBuildpackDir, 0755); err != nil {
235-
return fmt.Errorf("failed to create .java-buildpack directory: %w", err)
236-
}
237-
238-
startScript := filepath.Join(javaBuildpackDir, "start.sh")
227+
// writeReleaseYaml writes the release configuration to a YAML file
228+
// This follows the pattern used by Ruby, Go, and Node.js buildpacks
229+
func (f *Finalizer) writeReleaseYaml(container containers.Container) error {
230+
f.Log.BeginStep("Writing release configuration")
239231

240232
// Get the container's startup command
241233
containerCommand, err := container.Release()
242234
if err != nil {
243235
return fmt.Errorf("failed to get container command: %w", err)
244236
}
245237

246-
// Build startup script content
247-
scriptContent := fmt.Sprintf(`#!/bin/bash
248-
set -e
249-
250-
# Source profile.d scripts (sets JAVA_HOME, etc.)
251-
for script in $HOME/.profile.d/*.sh; do
252-
[ -r "$script" ] && source "$script"
253-
done
254-
255-
# Source memory calculator script
256-
if [ -r $DEPS_DIR/0/bin/memory_calculator.sh ]; then
257-
source $DEPS_DIR/0/bin/memory_calculator.sh
258-
fi
259-
260-
# Source environment variables
261-
if [ -d $DEPS_DIR/0/env ]; then
262-
for envfile in $DEPS_DIR/0/env/*; do
263-
[ -r "$envfile" ] && export $(basename "$envfile")="$(cat "$envfile")"
264-
done
265-
fi
266-
267-
# Execute application
268-
cd $HOME
269-
exec %s
238+
// Create tmp directory in build dir
239+
tmpDir := filepath.Join(f.Stager.BuildDir(), "tmp")
240+
if err := os.MkdirAll(tmpDir, 0755); err != nil {
241+
return fmt.Errorf("failed to create tmp directory: %w", err)
242+
}
243+
244+
// Write YAML file with release information
245+
releaseYamlPath := filepath.Join(tmpDir, "java-buildpack-release-step.yml")
246+
yamlContent := fmt.Sprintf(`---
247+
default_process_types:
248+
web: %s
270249
`, containerCommand)
271250

272-
// Write startup script
273-
if err := os.WriteFile(startScript, []byte(scriptContent), 0755); err != nil {
274-
return fmt.Errorf("failed to write startup script: %w", err)
251+
if err := os.WriteFile(releaseYamlPath, []byte(yamlContent), 0644); err != nil {
252+
return fmt.Errorf("failed to write release YAML: %w", err)
275253
}
276254

277-
f.Log.Info("Startup script generated: %s", startScript)
255+
f.Log.Info("Release YAML written: %s", releaseYamlPath)
256+
f.Log.Info("Web process command: %s", containerCommand)
278257
return nil
279258
}

src/java/release/release.go

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package release
22

33
import (
44
"fmt"
5+
"os"
6+
"path/filepath"
57

68
"github.com/cloudfoundry/libbuildpack"
79
)
@@ -13,13 +15,23 @@ type Releaser struct {
1315
}
1416

1517
// Run generates the release information
16-
// The release phase is simple - it just outputs the default process type (web command)
17-
// The actual startup command will be determined at runtime by the finalized container
18+
// This follows the reference buildpack pattern (Ruby, Go, Node.js, Python):
19+
// 1. Read the YAML file written by the finalize phase
20+
// 2. Output it to stdout for Cloud Foundry to parse
21+
// The YAML file contains the direct container command (e.g., bin/application for DistZip)
1822
func Run(r *Releaser) error {
19-
// Output default process types in YAML format
20-
// This must be valid YAML parseable by Cloud Foundry
21-
fmt.Println("---")
22-
fmt.Println("default_process_types:")
23-
fmt.Println(" web: $HOME/.java-buildpack/start.sh")
23+
releaseYamlPath := filepath.Join(r.BuildDir, "tmp", "java-buildpack-release-step.yml")
24+
25+
// Read the YAML file written by finalize phase
26+
yamlContent, err := os.ReadFile(releaseYamlPath)
27+
if err != nil {
28+
r.Log.Error("Failed to read release YAML file: %s", err.Error())
29+
return fmt.Errorf("reading release YAML: %w", err)
30+
}
31+
32+
// Output the YAML content to stdout
33+
// Cloud Foundry will parse this to determine the web command
34+
fmt.Print(string(yamlContent))
35+
2436
return nil
2537
}

src/java/release/release_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,20 @@ var _ = Describe("Release", func() {
3232
buildDir, err = os.MkdirTemp("", "release-build")
3333
Expect(err).NotTo(HaveOccurred())
3434

35+
// Create tmp directory for release YAML (simulating finalize phase)
36+
tmpDir := buildDir + "/tmp"
37+
err = os.MkdirAll(tmpDir, 0755)
38+
Expect(err).NotTo(HaveOccurred())
39+
40+
// Create release YAML file (simulating finalize phase output)
41+
releaseYamlPath := tmpDir + "/java-buildpack-release-step.yml"
42+
releaseYaml := `---
43+
default_process_types:
44+
web: $HOME/.java-buildpack/start.sh
45+
`
46+
err = os.WriteFile(releaseYamlPath, []byte(releaseYaml), 0644)
47+
Expect(err).NotTo(HaveOccurred())
48+
3549
// Create logger with buffer to capture output
3650
stdout = new(bytes.Buffer)
3751
logger = libbuildpack.NewLogger(stdout)

0 commit comments

Comments
 (0)