Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/release-process.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 1 addition & 4 deletions bin/release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 9 additions & 5 deletions packages/cli/bin/marko
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
19 changes: 14 additions & 5 deletions packages/cli/tests/BinMarkoTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
18 changes: 15 additions & 3 deletions packages/dev-server/tests/Command/DevDownCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});

Expand Down
40 changes: 36 additions & 4 deletions tests/IntegrationVerificationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'
<?php
[$root, $resultFile] = [$argv[1], $argv[2]];
[$root, $resultFile, $php, $isolatedRoot] = [$argv[1], $argv[2], $argv[3], $argv[4]];

$results = [];

function copyTree(string $source, string $destination): void
{
if (is_link($source)) {
symlink(readlink($source), $destination);

return;
}

if (is_file($source)) {
copy($source, $destination);

return;
}

if (!is_dir($destination)) {
mkdir($destination, 0777, true);
}

foreach (scandir($source) as $entry) {
if ($entry === '.' || $entry === '..' || $entry === '.git' || $entry === 'vendor') {
continue;
}

copyTree($source . '/' . $entry, $destination . '/' . $entry);
}
}

copyTree($root, $isolatedRoot);
$root = $isolatedRoot;

// Step 1: Remove lock and vendor
if (file_exists($root . '/composer.lock')) {
unlink($root . '/composer.lock');
Expand All @@ -74,7 +105,6 @@ function () use ($root): void {
$results['composer_update_output'] = implode("\n", array_slice($updateOutput, -5));

// Step 3: Run test suite (exclude destructive group to avoid recursion)
$php = '/opt/homebrew/Cellar/php/8.5.1_2/bin/php';
exec(
'cd ' . escapeshellarg($root) . ' && ' . $php . ' vendor/bin/pest --parallel --exclude-group=integration-destructive 2>&1',
$testOutput,
Expand All @@ -96,6 +126,8 @@ function () use ($root): void {
$php . ' ' . escapeshellarg($scriptFile)
. ' ' . escapeshellarg($root)
. ' ' . escapeshellarg($resultFile)
. ' ' . escapeshellarg($php)
. ' ' . escapeshellarg($isolatedRoot)
. ' 2>/dev/null',
);

Expand All @@ -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(
Expand Down
6 changes: 2 additions & 4 deletions tests/ReleaseScriptTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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');
});

Expand Down