PHPStan (level 6 + symfony extension) and PHP CS Fixer (Symfony + PHP83Migration ruleset) configs at framework/php/. composer.json exposes phpstan / cs:check / cs:fix / phpunit / quality scripts. PHPStan-clean across the bundle; cs:check is happy after auto-fix applied @Symfony idioms (yoda, leading-backslash JSON_*, blank-line before return). Test mocks consolidated into a HubSpy helper to keep PHPStan happy about by-ref captures. Skeleton's Makefile target `quality` chains `composer quality` (in framework/php/) with cmake's all_qmllint target. Local run is green — 11 tests / 32 assertions, no PHPStan errors, cs-fixer clean, qmllint emits advisory warnings only. Layout fix in skeleton's Main.qml: status-dot Rectangles inside RowLayout now use Layout.preferredWidth/Height instead of width/height to satisfy Quick.layout-positioning checks. .gitea/workflows/ci.yml replaces the placeholder with a real `quality` job: setup-php, composer install (cached), the four PHP checks, Qt 6 via install-qt-action (cached), QML module build, qmllint via the all_qmllint CMake target. Workflow exists from this commit onward even if a runner isn't provisioned yet. bridge:doctor lost the Publisher dependency since it was only used as a "service is wired" marker — the command being injectable already proves that. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpQml\Bridge\Command;
|
||||
|
||||
use PhpQml\Bridge\Publisher;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
@@ -23,7 +22,6 @@ use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
final class BridgeDoctorCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Publisher $publisher,
|
||||
#[Autowire('%env(default::BRIDGE_TOKEN)%')]
|
||||
private readonly string $bridgeToken,
|
||||
#[Autowire('%env(default::MERCURE_URL)%')]
|
||||
@@ -47,34 +45,30 @@ final class BridgeDoctorCommand extends Command
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$io->title('php-qml bridge — readiness checks');
|
||||
|
||||
// PHP version + extensions are enforced by composer, so we don't
|
||||
// re-check them runtime — would always be true on a working install.
|
||||
$checks = [
|
||||
['PHP version >= 8.3',
|
||||
PHP_VERSION_ID >= 80300,
|
||||
'Upgrade PHP to 8.3 or newer; the bundle requires it.'],
|
||||
['ext-curl available',
|
||||
extension_loaded('curl'),
|
||||
'Install the PHP curl extension.'],
|
||||
['ext-json available',
|
||||
extension_loaded('json'),
|
||||
'Install the PHP json extension.'],
|
||||
['Publisher service wired',
|
||||
$this->publisher instanceof Publisher,
|
||||
'Bundle services failed to load — register PhpQml\\Bridge\\BridgeBundle in config/bundles.php.'],
|
||||
['BRIDGE_TOKEN env set',
|
||||
$this->bridgeToken !== '',
|
||||
'' !== $this->bridgeToken,
|
||||
'Set BRIDGE_TOKEN in .env.local; the Qt host expects this as the bearer token.'],
|
||||
['MERCURE_URL env set',
|
||||
$this->mercureUrl !== '',
|
||||
'' !== $this->mercureUrl,
|
||||
'Set MERCURE_URL in .env, e.g. http://127.0.0.1:8765/.well-known/mercure.'],
|
||||
['MERCURE_PUBLISHER_JWT_KEY env set',
|
||||
$this->mercurePublisherKey !== '',
|
||||
'' !== $this->mercurePublisherKey,
|
||||
'Set MERCURE_PUBLISHER_JWT_KEY in .env.local; mercure-bundle uses it to sign publish requests.'],
|
||||
['MERCURE_SUBSCRIBER_JWT_KEY env set',
|
||||
$this->mercureSubscriberKey !== '',
|
||||
'' !== $this->mercureSubscriberKey,
|
||||
'Set MERCURE_SUBSCRIBER_JWT_KEY in .env.local; or rely on the Caddy `anonymous` directive in dev mode.'],
|
||||
];
|
||||
|
||||
$rows = [];
|
||||
$rows = [];
|
||||
$allPass = true;
|
||||
foreach ($checks as [$label, $ok, $hint]) {
|
||||
$rows[] = [
|
||||
@@ -100,10 +94,12 @@ final class BridgeDoctorCommand extends Command
|
||||
|
||||
if ($allPass) {
|
||||
$io->success('All checks passed. Bridge is ready.');
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$io->warning('Some checks failed — fix the items above before running the bridge.');
|
||||
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
@@ -120,17 +116,19 @@ final class BridgeDoctorCommand extends Command
|
||||
],
|
||||
]);
|
||||
$body = @file_get_contents($url, false, $ctx);
|
||||
if ($body === false) {
|
||||
if (false === $body) {
|
||||
$err = error_get_last()['message'] ?? 'unknown error';
|
||||
|
||||
return ['ok' => false, 'detail' => $err];
|
||||
}
|
||||
$statusLine = $http_response_header[0] ?? '';
|
||||
preg_match('#HTTP/\S+\s+(\d+)#', $statusLine, $m);
|
||||
$status = (int) ($m[1] ?? 0);
|
||||
|
||||
return [
|
||||
'ok' => $status === 200,
|
||||
'ok' => 200 === $status,
|
||||
'status' => $status,
|
||||
'detail' => $status === 200 ? '' : "expected 200, got {$status}",
|
||||
'detail' => 200 === $status ? '' : "expected 200, got {$status}",
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user