Skip to content

Conversation

@ramonskie
Copy link
Contributor

Summary

This PR completes the migration from Python-based build system to Go-based libbuildpack architecture. It removes all legacy Python infrastructure and adds a comprehensive test suite with 192 test specifications.

Key Changes

🗑️ Removed Python Infrastructure (~15,713 lines deleted)

  • Removed all Python-based build scripts (lib/, extensions/, compile-extensions/)
  • Removed Python test suite (tests/ directory with 13 test files)
  • Removed Python dependencies (requirements.txt, python-vendor/)
  • Removed Ruby/Python installation scripts

✅ Added Comprehensive Test Suite (+4,401 lines added)

  • 110 extension unit tests across 5 extensions (Composer, AppDynamics, NewRelic, Dynatrace, Sessions)
  • 48 supply/finalize phase unit tests
  • 19 integration tests (all passing)
  • Total: 192 test specifications with 100% pass rate

🔧 Critical Bug Fixes

  • Fixed PHP version selection from composer.json semantic versioning (>=, >, <=, <, ^, ~, ||)
  • Added composer.lock constraint validation (validates against ALL locked package PHP requirements)
  • Fixed CakePHP integration test (optional plugin handling)
  • Fixed phpredis test fixture (PHP 8.x compatibility)
  • Fixed regex support in ConfigFileEditor for php.ini modifications
  • Fixed error propagation in extension configuration

📋 Test Coverage Details

Extension Tests (110 specs):

  • Composer: 31 specs (version matching, constraint validation, lock file parsing)
  • AppDynamics: 22 specs (agent detection, configuration, download)
  • NewRelic: 22 specs (agent setup, license validation, environment config)
  • Dynatrace: 15 specs (agent installation, one-agent mode, manifest injection)
  • Sessions: 20 specs (Redis/Memcached handlers, VCAP_SERVICES parsing, php.ini updates)

Supply/Finalize Tests (48 specs):

  • Supply phase: 25 specs (dependency installation, extension processing, configuration)
  • Finalize phase: 21 specs (process setup, configuration finalization)
  • Options: 4 specs (loading, validation, merging defaults)

Integration Tests (19 specs):

  • 9 module tests (extensions, custom configs, AMQP, APCu, Argon2, phpredis)
  • 4 composer tests (default, custom path, error handling)
  • 4 web server tests (Nginx, httpd, fpm configuration)
  • 2 framework tests (CakePHP, Laminas)
  • 1 offline/vendored test

🎯 Migration Alignment

This implementation now matches the reference buildpack architecture:

  • Go-based build system (like go-buildpack, ruby-buildpack, python-buildpack)
  • libbuildpack integration
  • Proper supply/finalize phase separation
  • Comprehensive test coverage

Testing

✅ All 192 tests passing:

  • 19/19 integration tests
  • 173/173 unit tests
  • Both cached and uncached scenarios verified

Breaking Changes

⚠️ This is a major architectural change:

  • Removes all Python-based infrastructure
  • Requires Go 1.21+ for buildpack compilation
  • Build/package process updated to compile Go code

Migration Context

This PR represents the culmination of Sessions 31-35 of the migration effort:

  • Core Go implementation of all buildpack phases (detect, supply, finalize, release)
  • Complete extension system migration (5 extensions fully ported)
  • Comprehensive test suite development
  • Integration test fixes and PHP 8.x compatibility updates

Files Changed: 183 files (+4,401, -15,713)
Net Impact: -11,312 lines (removed more legacy code than added)
Test-to-Production Ratio: High test coverage for all critical paths

Replace deprecated Ruby gem-based packaging with Go-based buildpack-packager,
bringing the PHP buildpack in line with all other Cloud Foundry buildpacks.

Changes:
- Add buildpack-packager::install function to scripts/.util/tools.sh
- Refactor scripts/package.sh to use Go-based packager
- Delete obsolete cf.Gemfile and cf.Gemfile.lock
- Update README.md with modernized packaging instructions
- Remove cf.Gemfile references from manifest.yml exclude_files
- Modernize scripts/brats.sh to use Go-based packager
- Enable buildpack-packager install in scripts/integration.sh (consistent with other buildpacks)
- Remove newrelic from default_versions in manifest.yml

The newrelic removal is required because the Go-based packager correctly
validates semantic versions and rejects 4-part versions (10.21.0.11).
NewRelic remains fully functional at runtime via compile-extensions
fallback mechanism that automatically selects the single available
version from the dependencies section.

This change eliminates Docker and Ruby dependencies for packaging while
maintaining complete backward compatibility at runtime.

Stats: 8 files changed, 52 insertions(+), 99 deletions(-)
Add scripts/install_go.sh to download and install Go 1.22.5 during buildpack execution. This enables on-the-fly compilation of Go-based buildpack code, following the pattern used in the go-buildpack and ruby-buildpack reference implementations.
Implement supply, finalize, detect, release, start, and rewrite phases in Go:
- supply.go: Dependency installation, PHP/HTTPD/Nginx setup, extension management
- finalize.go: Final configuration and runtime preparation
- detect.go: Buildpack detection logic
- release.go: Release metadata generation
- start.go: Process manager for running multiple services
- rewrite.go: Configuration file template substitution

This migration aligns with Cloud Foundry's libbuildpack architecture used in reference buildpacks.
Convert all buildpack extensions to Go:
- extension.go: Base extension interface and lifecycle management
- appdynamics.go: AppDynamics APM integration
- composer.go: PHP Composer dependency management (856 lines)
- dynatrace.go: Dynatrace APM integration (524 lines)
- newrelic.go: New Relic APM integration
- sessions.go: PHP session storage configuration

Each extension implements compile-time and runtime hooks for modifying buildpack behavior.
Implement configuration system with embedded defaults:
- config.go: Configuration file discovery and management
- options.go: Options parsing from options.json with validation
- hooks.go: Lifecycle hook definitions
- config/defaults/: Embedded default configs for HTTPD, Nginx, PHP-FPM

Embedded defaults enable the buildpack to function without external dependencies. Includes comprehensive unit tests for options parsing.
Replace Python-based scripts with Go compilation wrappers:
- bin/detect: Compile and run detect.go
- bin/supply: Compile and run supply.go
- bin/finalize: Compile and run finalize.go
- bin/release: Compile and run release.go
- bin/start: Compile and run start.go
- bin/rewrite: Compile and run rewrite.go

All scripts follow consistent pattern: install Go, compile binary with -mod=vendor, execute with arguments. This matches the architecture of reference Cloud Foundry buildpacks.
Adjust integration test setup to work with Go compilation:
- init_test.go: Update test initialization and buildpack path handling
- apms_test.go: Update APM integration test expectations
- app_frameworks_test.go: Minor cleanup
- composer_test.go: Update Composer test expectations

Tests now account for Go compilation step during buildpack execution.
Add ARCHITECTURE.md (635 lines) documenting:
- Migration rationale and goals
- Go-based buildpack architecture
- Supply/finalize phase separation
- Extension system design
- Configuration management approach
- Comparison with Python implementation

Update .gitignore to exclude Go build artifacts and temporary files.
Complete the Python-to-Go migration by adding pre-compilation build infrastructure. The buildpack now compiles Go binaries during packaging (via scripts/build.sh) instead of at runtime, matching the architecture of reference buildpacks.

Changes:
- Add scripts/build.sh to compile all Go CLI binaries during packaging
- Update manifest.yml with pre_package directive and explicit include_files
- Make bin/supply executable to match other wrapper scripts
- Remove conflicting exclude_files section from manifest

This eliminates runtime Go compilation dependencies and produces smaller, faster packaged buildpacks containing only ELF binaries and documentation.
All Python buildpack functionality has been reimplemented in Go with enhanced features:
- 5 extensions migrated (appdynamics, composer, dynatrace, newrelic, sessions)
- Web server support (httpd, nginx, none) integrated into supply phase
- Helper libraries replaced with Go extension system and libbuildpack
- Python unit tests replaced with Go integration/unit/BRATS tests
- Eliminates runtime dependency on Python/Ruby during buildpack execution

Removed:
- Python/Ruby runtime installers (bin/install-python, bin/install-ruby)
- Python build scripts (scripts/{compile,detect,release}.py)
- Python extension implementations (extensions/*/extension.py)
- Python helper libraries (lib/build_pack_utils/, lib/*_helpers.py)
- Vendored YAML library (lib/yaml/*)
- Python test suite (tests/*.py)
- Python dependencies (requirements.txt, compile-extensions submodule)
- Python/Ruby manifest.yml dependencies (3 entries)
Implement semantic version matching and context-to-options sync to resolve
CakePHP integration test failure where buildpack attempted to install
non-existent PHP 7.0.28 instead of matching available versions against
composer.json constraint.

Changes:
- composer.go: Implement full semantic version matching (~310 lines)
  * Support for >=, >, <=, <, ^, ~, || constraints
  * Wildcard and exact version matching
  * Version comparison and constraint evaluation logic
- supply.go: Bridge context/options gap
  * Sync PHP_VERSION from extension context to Options after Configure
  * Provide ALL_PHP_VERSIONS list for version matching
- AGENTS.md: Document Session 32 debugging and solution
The composer extension now checks PHP requirements from ALL locked packages
in composer.lock, not just the composer.json constraint. This ensures the
selected PHP version satisfies both the application's requirement and all
locked dependencies' requirements.

Previously, the buildpack would select the highest PHP version matching
composer.json (e.g., 8.3.21 for '>=7.4'), but this could conflict with
locked packages requiring older versions (e.g., laminas packages requiring
~8.0.0 || ~8.1.0 || ~8.2.0), causing composer install to fail at runtime.

Now selects the highest PHP version satisfying ALL constraints (e.g., 8.2.28
for CakePHP fixture with laminas dependencies).

Changes:
- Add readPHPConstraintsFromLock() to parse package PHP requirements
- Update pickPHPVersion() to accept lockConstraints parameter
- Filter available versions against all constraints simultaneously
- Add informational output showing number of locked dependency constraints
Update test fixtures to work with PHP 8.x-only manifest and proper CakePHP
plugin loading patterns.

Changes:
1. CakePHP fixture: Use addOptionalPlugin() for DebugKit instead of
   addPlugin(). DebugKit is a dev dependency (require-dev) that is not
   installed during buildpack compilation (--no-dev flag). The
   addOptionalPlugin() method fails gracefully when the plugin is missing,
   matching the pattern used for other dev dependencies (Bake, Repl).

2. phpredis fixture: Update PHP_VERSION from 7.0.28 (EOL, not in manifest)
   to 8.2.28 (supported). The buildpack manifest only contains PHP 8.x
   versions, so tests must request supported versions.

These fixes resolve the remaining integration test failures.
Remove all PHP 7.x version references from test fixtures to reflect
buildpack's PHP 8.1+ requirement. End-of-life PHP 7.x is no longer
supported.

Changes:
- fixtures/cake/composer.json: php >=7.4 → >=8.1
- fixtures/laminas/composer.json: php ^7.4||~8.0||~8.1||~8.2 → ~8.1||~8.2||~8.3
- fixtures/laminas/renovate.json: php ^7.4 → ^8.1
- fixtures/laminas/README.md: Update Vagrant docs (PHP 7.3 → 8.3)

All 19 integration tests still passing.
Expand test coverage from 21 to 46 unit test specifications to match
reference buildpack testing patterns (go-buildpack, ruby-buildpack).

Supply Tests (25 specs, 633 lines):
- Stager interface operations (directory linking, env files, profile.d)
- InstallPHP method (specified version, default version)
- InstallWebServer method (httpd, nginx, none)
- CreateDefaultEnv (environment variable management)
- Manifest interface (version queries, cached buildpack detection)
- Enhanced test stubs with tracking capabilities

Finalize Tests (21 specs, 809 lines):
- CreateStartScript with all web server types (httpd, nginx, php-fpm)
- Start script file management (.bp/bin structure, rewrite binary)
- Web server configuration (custom WEBDIR, default values)
- Error handling (missing BP_DIR, invalid options.json)
- Pre-start script generation validation
- Process type setup (Procfile handling)

Test Quality:
- Simple test stubs (no complex mocking)
- Focus on observable behavior (files, content, errors)
- Real filesystem operations with temp directories
- Comprehensive error case coverage
- Clear Arrange-Act-Assert pattern

All 46 unit tests passing + 19 integration tests = 65+ total test specs
Coverage matches or exceeds reference buildpack implementations.
- Add 110 new test specifications across 5 extensions
- Composer: 31 specs testing version matching, constraints, lock validation
- AppDynamics: 22 specs testing agent detection and configuration
- NewRelic: 22 specs testing agent setup and license handling
- Dynatrace: 15 specs testing agent installation and configuration
- Sessions: 20 specs testing session handler configuration

Bug fixes discovered during test development:
- Fix composer.go error propagation for invalid JSON
- Fix OR constraint matching to return highest version, not first
- Fix AND constraint evaluation order
- Fix versionMatchesConstraint to handle compound constraints

Total test coverage now: 192 specs (19 integration + 173 unit)
All tests passing.
- Fix extension.go UpdateLines() to support regex patterns
  - Was only doing exact string matching despite accepting regex patterns
  - Sessions extension needs regex for php.ini modifications
  - Added regexp compilation and matching logic

- Fix options_test.go InvalidWebServer test
  - Was testing invalid embedded defaults (impossible scenario)
  - Now tests invalid user configuration (actual failure case)
  - Tests runtime validation of user-provided options.json
@ramonskie ramonskie mentioned this pull request Nov 11, 2025
@beyhan
Copy link
Member

beyhan commented Nov 12, 2025

Ping @cloudfoundry/wg-app-runtime-interfaces-buildpacks-and-stacks-reviewers because this could be a good review opportunity.

@wayneeseguin
Copy link

Firstly, introducing the go packager 💯 , excellent.

Since now we have PHP >= 8.1 from 7.4, should the CHANGELOG/README.md/release notes etc... mention that 7.4 no longer supported?

Since this is a good "big" bump, should this become a major version? (5.0.0?)

w.r.t. the CI failures, since ./run_tests.sh, bin/install-python, and the python test files were all deleted (good!) in the commit, should we also delete src/php/unit/python_unit_specs_test.go which tries to run them?

For the fact that we're now using the go buildpack packaging approach (awesome!) should we add docs on how to run it to build the buildpack now? (Maybe I missed it).

- Remove all Python buildpack references (PyEnv, virtualenv, pip, Python 2.6.6)
- Update build instructions to use buildpack-packager and direnv
- Change testing framework documentation from Cutlass to Switchblade
- Update project structure to reflect Go source layout (src/php/*)
- Document complete buildpack lifecycle with build-time and runtime phases
- Add detailed documentation for rewrite phase (config templating)
- Modernize extensions section with Go interface examples
- Remove obsolete python_unit_specs_test.go that referenced non-existent Python test infrastructure
@ramonskie
Copy link
Contributor Author

ramonskie commented Nov 14, 2025

7.4 was already not supported in the old pyhton based buildpack. i did not mess with any of the supported version.
i just updated the test so that they reflected the truth.

i just updated the readme so that it reflects our current status (i love ai for this, as i cant write any propper documentation..
)

@wayneeseguin
Copy link

7.4 was already not supported in the old pyhton based buildpack. i did not mess with any of the supported version. i just updated the test so that they reflected the truth.

i just updated the readme so that it reflects our current status (i love ai for this, as i cant write any propper documentation.. )

OK, sounds great, and I completely agree - I use AI for commit messages especially have it generate then edit a bit so helpful.

I don't have anything to add so this from my perspective "LGTM"

@rkoster rkoster requested a review from Copilot November 14, 2025 17:28
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR completes the migration from a Python-based build system to a Go-based libbuildpack architecture, removing approximately 15,713 lines of legacy Python code while adding 4,401 lines of new Go implementation and comprehensive test coverage (192 test specifications with 100% pass rate).

Key Changes

  • Removed entire Python infrastructure including build scripts, test suite, and Python/Ruby dependencies
  • Added comprehensive Go-based test suite covering extensions, supply/finalize phases, and integration tests
  • Introduced Go-based configuration system with embedded default configs
  • Updated build/package process to use Go compilation and buildpack-packager
  • Removed Python and Ruby runtime dependencies from manifest

Reviewed Changes

Copilot reviewed 93 out of 242 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/php/config/defaults/config/php/8.3.x/php-fpm.conf Added PHP-FPM 8.3.x default configuration
src/php/config/defaults/config/php/8.2.x/php.ini Added PHP 8.2.x default php.ini configuration
src/php/config/defaults/config/php/8.2.x/php-fpm.conf Added PHP-FPM 8.2.x default configuration
src/php/config/defaults/config/php/8.1.x/php.ini Added PHP 8.1.x default php.ini configuration
src/php/config/defaults/config/php/8.1.x/php-fpm.conf Added PHP-FPM 8.1.x default configuration
src/php/config/defaults/config/nginx/*.conf Added Nginx default configurations for server, locations, logging, etc.
src/php/config/defaults/config/httpd/*.conf Added Apache httpd default configurations with proxy support
src/php/config/config.go Implemented Go package for embedded config file extraction and management
scripts/release.py Removed Python-based release script
scripts/package.sh Updated to use buildpack-packager instead of Docker-based Ruby packaging
scripts/integration.sh Re-enabled buildpack-packager installation
scripts/install_go.sh Added Go 1.22.5 installation script for build environment
scripts/detect.py Removed Python-based detect script
scripts/compile.py Removed Python-based compile script
scripts/build.sh Added Go build script for compiling buildpack binaries
scripts/brats.sh Updated to use buildpack-packager instead of Ruby bundler
scripts/.util/tools.sh Added buildpack-packager installation utility
run_tests.sh Removed Python test runner
manifest.yml Removed Python/Ruby dependencies; updated to use Go pre_package build
lib/yaml/*.py Removed Python YAML library (multiple files)
lib/build_pack_utils/__init__.py Removed Python build pack utilities

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

@ivanovac ivanovac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@ramonskie ramonskie merged commit 45abe57 into master Nov 24, 2025
4 of 6 checks passed
@ramonskie ramonskie deleted the go-migration branch November 24, 2025 20:49
@ramonskie
Copy link
Contributor Author

related to cloudfoundry/buildpacks-ci#497

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants