From 99cf6a0a5bbd99460ef9698ba1684521cc54e163 Mon Sep 17 00:00:00 2001 From: m1rm Date: Sat, 11 Apr 2026 11:07:07 +0200 Subject: [PATCH 1/3] feat: improve deployer singleton handling by accounting for uninitialized state --- src/Deployer.php | 19 ++++++++++++++++++- src/Host/Host.php | 2 +- tests/src/Host/HostTest.php | 6 ++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/Deployer.php b/src/Deployer.php index 436299568..bdb3c5e1e 100755 --- a/src/Deployer.php +++ b/src/Deployer.php @@ -66,7 +66,7 @@ */ class Deployer extends Container { - private static Deployer $instance; + private static ?self $instance = null; public function __construct(Application $console) { @@ -167,9 +167,26 @@ public function __construct(Application $console) public static function get(): self { + if (self::$instance === null) { + throw new \RuntimeException('Deployer is not initialized.'); + } + return self::$instance; } + public static function hasInstance(): bool + { + return self::$instance !== null; + } + + /** + * @internal For tests that need a clean Deployer singleton between cases. + */ + public static function resetInstance(): void + { + self::$instance = null; + } + public function init(): void { $this->addTaskCommands(); diff --git a/src/Host/Host.php b/src/Host/Host.php index 093794ae0..fd90d0823 100644 --- a/src/Host/Host.php +++ b/src/Host/Host.php @@ -29,7 +29,7 @@ class Host public function __construct(string $hostname) { $parent = null; - if (Deployer::get()) { + if (Deployer::hasInstance()) { $parent = Deployer::get()->config; } $this->config = new Configuration($parent); diff --git a/tests/src/Host/HostTest.php b/tests/src/Host/HostTest.php index 529027222..e59b86f55 100644 --- a/tests/src/Host/HostTest.php +++ b/tests/src/Host/HostTest.php @@ -8,10 +8,16 @@ namespace Deployer\Host; use Deployer\Configuration; +use Deployer\Deployer; use PHPUnit\Framework\TestCase; class HostTest extends TestCase { + protected function tearDown(): void + { + Deployer::resetInstance(); + } + public function testHost() { $host = new Host('host'); From 516112860ad5ef7a17519af7b28c2521c8d07cee Mon Sep 17 00:00:00 2001 From: Miriam Date: Sun, 12 Apr 2026 18:54:27 +0200 Subject: [PATCH 2/3] dev(address-review): Deployer::get() already throws \RuntimeException('Deployer is not initialized.') when the singleton is missing, so the constructor now always uses the deployer config as the parent and relies on that throw (no separate if (!Deployer::hasInstance()) block needed --- src/Deployer.php | 5 ----- src/Host/Host.php | 5 +---- tests/src/Host/HostTest.php | 6 ++++++ tests/src/Selector/SelectorTest.php | 12 ++++++++++++ tests/src/Task/TaskTest.php | 13 +++++++++++++ 5 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/Deployer.php b/src/Deployer.php index bdb3c5e1e..7ff3cf4f4 100755 --- a/src/Deployer.php +++ b/src/Deployer.php @@ -174,11 +174,6 @@ public static function get(): self return self::$instance; } - public static function hasInstance(): bool - { - return self::$instance !== null; - } - /** * @internal For tests that need a clean Deployer singleton between cases. */ diff --git a/src/Host/Host.php b/src/Host/Host.php index fd90d0823..bb3765756 100644 --- a/src/Host/Host.php +++ b/src/Host/Host.php @@ -28,10 +28,7 @@ class Host public function __construct(string $hostname) { - $parent = null; - if (Deployer::hasInstance()) { - $parent = Deployer::get()->config; - } + $parent = Deployer::get()->config; $this->config = new Configuration($parent); $this->set('#alias', $hostname); $this->set('hostname', preg_replace('/\/.+$/', '', $hostname)); diff --git a/tests/src/Host/HostTest.php b/tests/src/Host/HostTest.php index e59b86f55..11aee0776 100644 --- a/tests/src/Host/HostTest.php +++ b/tests/src/Host/HostTest.php @@ -10,9 +10,15 @@ use Deployer\Configuration; use Deployer\Deployer; use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Application; class HostTest extends TestCase { + protected function setUp(): void + { + new Deployer(new Application()); + } + protected function tearDown(): void { Deployer::resetInstance(); diff --git a/tests/src/Selector/SelectorTest.php b/tests/src/Selector/SelectorTest.php index d8dc61a99..fd7335445 100644 --- a/tests/src/Selector/SelectorTest.php +++ b/tests/src/Selector/SelectorTest.php @@ -2,12 +2,24 @@ namespace Deployer\Selector; +use Deployer\Deployer; use Deployer\Host\Host; use Deployer\Host\HostCollection; use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Application; class SelectorTest extends TestCase { + protected function setUp(): void + { + new Deployer(new Application()); + } + + protected function tearDown(): void + { + Deployer::resetInstance(); + } + public function testSelectHosts() { $prod = (new Host('prod.domain.com'))->set('labels', ['stage' => 'prod']); diff --git a/tests/src/Task/TaskTest.php b/tests/src/Task/TaskTest.php index 040a097a3..9b2cf8552 100644 --- a/tests/src/Task/TaskTest.php +++ b/tests/src/Task/TaskTest.php @@ -7,8 +7,12 @@ namespace Deployer\Task; +use Deployer\Deployer; use Deployer\Host\Host; use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Input\Input; +use Symfony\Component\Console\Output\Output; use function Deployer\invoke; use function Deployer\task; @@ -20,9 +24,18 @@ public function callback(): void; class TaskTest extends TestCase { + protected function setUp(): void + { + $console = new Application(); + $deployer = new Deployer($console); + $deployer['input'] = $this->createStub(Input::class); + $deployer['output'] = $this->createStub(Output::class); + } + protected function tearDown(): void { StubTask::$runned = 0; + Deployer::resetInstance(); } public function testTask() From af234a6a43d007f51079936963c43748e2a52280 Mon Sep 17 00:00:00 2001 From: Miriam Date: Sun, 12 Apr 2026 18:56:37 +0200 Subject: [PATCH 3/3] dev(address-review): fix phpstan; old reported error no longer present due to refactoring --- tests/phpstan-baseline.neon | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/phpstan-baseline.neon b/tests/phpstan-baseline.neon index 96ca003a0..a014785c0 100644 --- a/tests/phpstan-baseline.neon +++ b/tests/phpstan-baseline.neon @@ -15,11 +15,6 @@ parameters: count: 1 path: ../src/Command/BlackjackCommand.php - - - message: "#^If condition is always true\\.$#" - count: 1 - path: ../src/Host/Host.php - - message: "#^Unreachable statement \\- code above always terminates\\.$#" count: 1