Skip to content
Open
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
1 change: 1 addition & 0 deletions packages/dev-server/config/dev.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

return [
'port' => 8000,
'host' => 'localhost',
'detach' => true,
'docker' => true,
'frontend' => true,
Expand Down
5 changes: 3 additions & 2 deletions packages/dev-server/src/Command/DevUpCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public function execute(
): int {
$port = (int) ($input->getOption('port') ?? $input->getOption('p') ?? $this->config->getInt('dev.port'));
$foreground = $input->hasOption('foreground') || $input->hasOption('f');
$host = $input->getOption('host') ?? $input->getOption('h') ?? $this->config->getString('dev.host');
$detach = !$foreground && ($input->hasOption('detach') || $input->hasOption('d') || $this->config->getBool(
'dev.detach',
));
Expand Down Expand Up @@ -156,8 +157,8 @@ public function execute(
}

// PHP server (always) β€” multiple workers needed for SSE
$phpCommand = "env PHP_CLI_SERVER_WORKERS=4 php -S localhost:$port -t public/";
$output->writeLine(" Starting PHP server: php -S localhost:$port");
$phpCommand = "env PHP_CLI_SERVER_WORKERS=4 php -S {$host}:{$port} -t public/";
$output->writeLine(" Starting PHP server: php -S {$host}:{$port}");
$pid = $startProcess('php', $phpCommand);

// In foreground mode, verify PHP server is alive β€” if it died, port is likely in use.
Expand Down
81 changes: 40 additions & 41 deletions packages/dev-server/tests/Command/DevUpCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ public function runForeground(): void
}
}

const CONFIG_DEFAULTS = [
'dev.port' => 8000,
'dev.host' => 'localhost',
'dev.docker' => false,
'dev.frontend' => false,
'dev.pubsub' => false,
'dev.detach' => true,
'dev.processes' => [],
];

/**
* Helper to create a DevUpCommand with standard test dependencies.
*
Expand All @@ -85,15 +95,7 @@ function createDevUpCommand(
file_put_contents($dir . '/public/index.php', '<?php');
}

$configDefaults = [
'dev.port' => 8000,
'dev.docker' => false,
'dev.frontend' => false,
'dev.pubsub' => false,
'dev.detach' => true,
'dev.processes' => [],
];
$fakeConfig = new FakeConfigRepository(array_merge($configDefaults, $config));
$fakeConfig = new FakeConfigRepository(array_merge(CONFIG_DEFAULTS, $config));

$dockerDetector = new DockerDetector($dir);
$frontendDetector = new FrontendDetector($dir);
Expand Down Expand Up @@ -150,6 +152,16 @@ function readStream(mixed $stream): string
expect($pm->started['php'])->toContain('localhost:7500');
});

it('reads host from config', function (): void {
['command' => $command, 'processManager' => $pm] = createDevUpCommand(['dev.host' => '127.0.0.1']);
['output' => $output] = createMemoryOutput();

$input = new Input(['marko', 'dev:up']);
$command->execute($input, $output);

expect($pm->started['php'])->toContain('127.0.0.1:8000');
});

it('reads docker setting from config', function (): void {
['command' => $command, 'processManager' => $pm] = createDevUpCommand([
'dev.docker' => 'custom-docker-up',
Expand Down Expand Up @@ -417,6 +429,17 @@ function readStream(mixed $stream): string
expect($pm->started['php'])->toContain('localhost:9000');
});

it('overrides config port with -h short flag', function (): void {
['command' => $command, 'processManager' => $pm] = createDevUpCommand(['dev.host' => 'localhost']);
['output' => $output] = createMemoryOutput();

$input = new Input(['marko', 'dev:up', '-h=0.0.0.0']);
$command->execute($input, $output);

expect($pm->started['php'])->toContain('0.0.0.0:8000');
});


it('overrides config port with -p space syntax', function (): void {
['command' => $command, 'processManager' => $pm] = createDevUpCommand(['dev.port' => 8000]);
['output' => $output] = createMemoryOutput();
Expand Down Expand Up @@ -520,7 +543,7 @@ function readStream(mixed $stream): string
$command->execute($input, $output);

$entries = $pidFile->read();
$names = array_map(fn ($e) => $e->name, $entries);
$names = array_map(fn($e) => $e->name, $entries);

expect($names)->toContain('tailwind')
->and($names)->toContain('php');
Expand All @@ -544,7 +567,7 @@ function readStream(mixed $stream): string
});

it('starts pubsub:listen as managed process in DevUpCommand when detected', function (): void {
$pubsubDetector = new class () extends PubSubDetector
$pubsubDetector = new class() extends PubSubDetector
{
protected function isPubSubInstalled(): bool
{
Expand All @@ -570,14 +593,7 @@ protected function isPubSubInstalled(): bool
mkdir($dir, 0755, true);
// Deliberately no public/index.php created

$fakeConfig = new FakeConfigRepository([
'dev.port' => 8000,
'dev.docker' => false,
'dev.frontend' => false,
'dev.pubsub' => false,
'dev.detach' => false,
'dev.processes' => [],
]);
$fakeConfig = new FakeConfigRepository(CONFIG_DEFAULTS);
$command = new DevUpCommand(
config: $fakeConfig,
dockerDetector: new DockerDetector($dir),
Expand All @@ -597,14 +613,7 @@ protected function isPubSubInstalled(): bool
$dir = sys_get_temp_dir() . '/marko-no-index-msg-' . uniqid();
mkdir($dir, 0755, true);

$fakeConfig = new FakeConfigRepository([
'dev.port' => 8000,
'dev.docker' => false,
'dev.frontend' => false,
'dev.pubsub' => false,
'dev.detach' => false,
'dev.processes' => [],
]);
$fakeConfig = new FakeConfigRepository(CONFIG_DEFAULTS);
$command = new DevUpCommand(
config: $fakeConfig,
dockerDetector: new DockerDetector($dir),
Expand Down Expand Up @@ -632,14 +641,11 @@ protected function isPubSubInstalled(): bool
$dir = sys_get_temp_dir() . '/marko-no-index-proc-' . uniqid();
mkdir($dir, 0755, true);

$fakeConfig = new FakeConfigRepository([
'dev.port' => 8000,
$fakeConfig = new FakeConfigRepository(array_merge(CONFIG_DEFAULTS, [
'dev.docker' => 'docker compose up',
'dev.frontend' => 'yarn dev',
'dev.pubsub' => false,
'dev.detach' => false,
'dev.processes' => [],
]);
]));
$pm = new FakeProcessManager();
$command = new DevUpCommand(
config: $fakeConfig,
Expand Down Expand Up @@ -668,14 +674,7 @@ protected function isPubSubInstalled(): bool
mkdir($dir . '/public', 0755, true);
file_put_contents($dir . '/public/index.php', '<?php');

$fakeConfig = new FakeConfigRepository([
'dev.port' => 8000,
'dev.docker' => false,
'dev.frontend' => false,
'dev.pubsub' => false,
'dev.detach' => false,
'dev.processes' => [],
]);
$fakeConfig = new FakeConfigRepository(CONFIG_DEFAULTS);
$pm = new FakeProcessManager();
$command = new DevUpCommand(
config: $fakeConfig,
Expand Down Expand Up @@ -773,7 +772,7 @@ protected function isPubSubInstalled(): bool
});

it('skips pubsub process when pubsub config is false', function (): void {
$pubsubDetector = new class () extends PubSubDetector
$pubsubDetector = new class() extends PubSubDetector
{
protected function isPubSubInstalled(): bool
{
Expand Down