Skip to content

Commit 2cb259a

Browse files
authored
feat: guard Deployer singleton before Host construction (#4189)
* feat: improve deployer singleton handling by accounting for uninitialized state * 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 * dev(address-review): fix phpstan; old reported error no longer present due to refactoring
1 parent 0b3b218 commit 2cb259a

File tree

6 files changed

+51
-10
lines changed

6 files changed

+51
-10
lines changed

src/Deployer.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
*/
6767
class Deployer extends Container
6868
{
69-
private static Deployer $instance;
69+
private static ?self $instance = null;
7070

7171
public function __construct(Application $console)
7272
{
@@ -167,9 +167,21 @@ public function __construct(Application $console)
167167

168168
public static function get(): self
169169
{
170+
if (self::$instance === null) {
171+
throw new \RuntimeException('Deployer is not initialized.');
172+
}
173+
170174
return self::$instance;
171175
}
172176

177+
/**
178+
* @internal For tests that need a clean Deployer singleton between cases.
179+
*/
180+
public static function resetInstance(): void
181+
{
182+
self::$instance = null;
183+
}
184+
173185
public function init(): void
174186
{
175187
$this->addTaskCommands();

src/Host/Host.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,7 @@ class Host
2828

2929
public function __construct(string $hostname)
3030
{
31-
$parent = null;
32-
if (Deployer::get()) {
33-
$parent = Deployer::get()->config;
34-
}
31+
$parent = Deployer::get()->config;
3532
$this->config = new Configuration($parent);
3633
$this->set('#alias', $hostname);
3734
$this->set('hostname', preg_replace('/\/.+$/', '', $hostname));

tests/phpstan-baseline.neon

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,6 @@ parameters:
1515
count: 1
1616
path: ../src/Command/BlackjackCommand.php
1717

18-
-
19-
message: "#^If condition is always true\\.$#"
20-
count: 1
21-
path: ../src/Host/Host.php
22-
2318
-
2419
message: "#^Unreachable statement \\- code above always terminates\\.$#"
2520
count: 1

tests/src/Host/HostTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,22 @@
88
namespace Deployer\Host;
99

1010
use Deployer\Configuration;
11+
use Deployer\Deployer;
1112
use PHPUnit\Framework\TestCase;
13+
use Symfony\Component\Console\Application;
1214

1315
class HostTest extends TestCase
1416
{
17+
protected function setUp(): void
18+
{
19+
new Deployer(new Application());
20+
}
21+
22+
protected function tearDown(): void
23+
{
24+
Deployer::resetInstance();
25+
}
26+
1527
public function testHost()
1628
{
1729
$host = new Host('host');

tests/src/Selector/SelectorTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,24 @@
22

33
namespace Deployer\Selector;
44

5+
use Deployer\Deployer;
56
use Deployer\Host\Host;
67
use Deployer\Host\HostCollection;
78
use PHPUnit\Framework\TestCase;
9+
use Symfony\Component\Console\Application;
810

911
class SelectorTest extends TestCase
1012
{
13+
protected function setUp(): void
14+
{
15+
new Deployer(new Application());
16+
}
17+
18+
protected function tearDown(): void
19+
{
20+
Deployer::resetInstance();
21+
}
22+
1123
public function testSelectHosts()
1224
{
1325
$prod = (new Host('prod.domain.com'))->set('labels', ['stage' => 'prod']);

tests/src/Task/TaskTest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@
77

88
namespace Deployer\Task;
99

10+
use Deployer\Deployer;
1011
use Deployer\Host\Host;
1112
use PHPUnit\Framework\TestCase;
13+
use Symfony\Component\Console\Application;
14+
use Symfony\Component\Console\Input\Input;
15+
use Symfony\Component\Console\Output\Output;
1216

1317
use function Deployer\invoke;
1418
use function Deployer\task;
@@ -20,9 +24,18 @@ public function callback(): void;
2024

2125
class TaskTest extends TestCase
2226
{
27+
protected function setUp(): void
28+
{
29+
$console = new Application();
30+
$deployer = new Deployer($console);
31+
$deployer['input'] = $this->createStub(Input::class);
32+
$deployer['output'] = $this->createStub(Output::class);
33+
}
34+
2335
protected function tearDown(): void
2436
{
2537
StubTask::$runned = 0;
38+
Deployer::resetInstance();
2639
}
2740

2841
public function testTask()

0 commit comments

Comments
 (0)