diff --git a/.claude/release-process.md b/.claude/release-process.md index 68404812..256d530c 100644 --- a/.claude/release-process.md +++ b/.claude/release-process.md @@ -222,7 +222,7 @@ Runtime env vars for bin scripts (not stored as secrets — passed at the comman **Tests fail before release** - Fix the failing tests. They must pass before tagging. -- Run locally: `/opt/homebrew/Cellar/php/8.5.1_2/bin/php vendor/bin/pest --parallel` +- Run locally: `php vendor/bin/pest --parallel` (ensure PHP 8.5+ is on your PATH, or set `PHP_BIN` env var) **`composer update` fails locally** - Always run from the repo root (not inside a package directory) diff --git a/bin/release.sh b/bin/release.sh index 77751dd0..66522047 100755 --- a/bin/release.sh +++ b/bin/release.sh @@ -32,10 +32,7 @@ if git rev-parse "$TAG" >/dev/null 2>&1; then fi # Find PHP 8.5+ binary -PHP_BIN="/opt/homebrew/Cellar/php/8.5.1_2/bin/php" -if [[ ! -x "$PHP_BIN" ]]; then - PHP_BIN="php" -fi +PHP_BIN="${PHP_BIN:-php}" PHP_VERSION=$("$PHP_BIN" -r 'echo PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION;') if [[ "$PHP_VERSION" != "8.5" ]]; then diff --git a/packages/cli/bin/marko b/packages/cli/bin/marko index 4905d0f7..261320e3 100755 --- a/packages/cli/bin/marko +++ b/packages/cli/bin/marko @@ -21,11 +21,15 @@ use Marko\Cli\CliKernel; use Marko\Cli\ProjectFinder; try { - $kernel = new CliKernel( - projectFinder: new ProjectFinder(), - ); - $exitCode = $kernel->run($argv); - exit($exitCode); + $projectFinder = new ProjectFinder(); + + if (($projectRoot = $projectFinder->find()) !== null) { + require_once "{$projectRoot}/vendor/autoload.php"; + } + + exit((new CliKernel( + projectFinder: $projectFinder, + ))->run($argv)); } catch (Throwable $e) { fwrite(STDERR, "Error: " . $e->getMessage() . PHP_EOL); exit(1); diff --git a/packages/cli/tests/BinMarkoTest.php b/packages/cli/tests/BinMarkoTest.php index 1ad5c58c..28e52ce2 100644 --- a/packages/cli/tests/BinMarkoTest.php +++ b/packages/cli/tests/BinMarkoTest.php @@ -24,21 +24,30 @@ $content = file_get_contents($binMarkoPath); expect($content)->toContain('use Marko\Cli\CliKernel') - ->and($content)->toContain('new CliKernel'); + ->and($content)->toContain('new CliKernel') + ->and($content)->toContain('projectFinder: $projectFinder'); }); it('passes argv to kernel run method', function () use ($binMarkoPath) { $content = file_get_contents($binMarkoPath); - expect($content)->toContain('$kernel->run($argv)'); + expect($content)->toContain('->run($argv)'); }); it('exits with code returned from kernel', function () use ($binMarkoPath) { $content = file_get_contents($binMarkoPath); - // Should capture exit code and use it - expect($content)->toContain('$exitCode') - ->and($content)->toContain('exit($exitCode)'); + expect($content)->toContain('exit((new CliKernel(') + ->and($content)->toContain('))->run($argv));'); +}); + +it('loads the project autoloader when a project root is found', function () use ($binMarkoPath) { + $content = file_get_contents($binMarkoPath); + + expect($content)->toContain('use Marko\Cli\ProjectFinder') + ->and($content)->toContain('$projectFinder = new ProjectFinder()') + ->and($content)->toContain('$projectFinder->find()') + ->and($content)->toContain('require_once "{$projectRoot}/vendor/autoload.php"'); }); it('handles uncaught exceptions gracefully', function () use ($binMarkoPath) { diff --git a/packages/dev-server/tests/Command/DevDownCommandTest.php b/packages/dev-server/tests/Command/DevDownCommandTest.php index 77e8c8bf..36c32ef3 100644 --- a/packages/dev-server/tests/Command/DevDownCommandTest.php +++ b/packages/dev-server/tests/Command/DevDownCommandTest.php @@ -304,10 +304,22 @@ function createDevDownCommand(array $config = [], ?string $tmpDir = null): array usleep(100000); // let signals propagate - // Both parent and child should be dead — process group killed - expect($pidFile->isProcessGroupRunning($parentPid))->toBeFalse(); - proc_close($proc); + + $groupRunning = true; + for ($i = 0; $i < 10; $i++) { + $groupRunning = $pidFile->isProcessGroupRunning($parentPid); + if ($groupRunning === false) { + break; + } + + usleep(50000); + } + + // Reap the parent process before asserting so zombie cleanup does not + // make the process group appear alive briefly on Linux. + expect($groupRunning)->toBeFalse(); + devDownRemoveDir($tmpDir); }); diff --git a/tests/IntegrationVerificationTest.php b/tests/IntegrationVerificationTest.php index fbfa9427..3f8962e8 100644 --- a/tests/IntegrationVerificationTest.php +++ b/tests/IntegrationVerificationTest.php @@ -43,15 +43,46 @@ function () use ($packagesRoot, $packages): void { it( 'removes composer.lock and vendor/ before running composer update to ensure clean resolution', function () use ($root): void { - $php = '/opt/homebrew/Cellar/php/8.5.1_2/bin/php'; + $php = PHP_BINARY; $resultFile = tempnam(sys_get_temp_dir(), 'marko_result_'); + $isolatedRoot = sys_get_temp_dir() . '/marko-clean-install-' . uniqid(); $script = <<<'SCRIPT' &1', $testOutput, @@ -96,6 +126,8 @@ function () use ($root): void { $php . ' ' . escapeshellarg($scriptFile) . ' ' . escapeshellarg($root) . ' ' . escapeshellarg($resultFile) + . ' ' . escapeshellarg($php) + . ' ' . escapeshellarg($isolatedRoot) . ' 2>/dev/null', ); @@ -121,7 +153,7 @@ function () use ($root): void { })->group('integration-destructive'); it('runs the full test suite and all tests pass', function () use ($root): void { - $php = '/opt/homebrew/Cellar/php/8.5.1_2/bin/php'; + $php = PHP_BINARY; $output = []; $exitCode = 0; exec( diff --git a/tests/ReleaseScriptTest.php b/tests/ReleaseScriptTest.php index 7499ffe0..f8eef484 100644 --- a/tests/ReleaseScriptTest.php +++ b/tests/ReleaseScriptTest.php @@ -67,12 +67,10 @@ ->and($contents)->toContain('Expected X.Y.Z'); }); -it('validates PHP version is 8.5+ (checks /opt/homebrew/Cellar/php/8.5.1_2/bin/php or system php)', function () use ($script): void { - // Script should check the Homebrew PHP path first, then fall back to system php +it('validates PHP version is 8.5+ (uses PHP_BIN env var or defaults to system php)', function () use ($script): void { $contents = file_get_contents($script); - expect($contents)->toContain('/opt/homebrew/Cellar/php/8.5.1_2/bin/php') - ->and($contents)->toContain('PHP_BIN="php"') + expect($contents)->toContain('PHP_BIN="${PHP_BIN:-php}"') ->and($contents)->toContain('8.5'); });