Skip to content

Commit 28be71f

Browse files
authored
Release/4.0.0 (#30)
1 parent e805edd commit 28be71f

101 files changed

Lines changed: 3720 additions & 3219 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎README.md‎

Lines changed: 314 additions & 158 deletions
Large diffs are not rendered by default.

‎composer.json‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,12 @@
2525
"php": "^8.5",
2626
"symfony/process": "^8.1",
2727
"tiny-blocks/collection": "^2.6",
28-
"tiny-blocks/ksuid": "^2.0"
28+
"tiny-blocks/ksuid": "^2.0",
29+
"tiny-blocks/time": "^2.7"
2930
},
3031
"require-dev": {
3132
"ergebnis/composer-normalize": "^2.52",
32-
"infection/infection": "^0.34",
33+
"infection/infection": "^0.35",
3334
"phpstan/phpstan": "^2.2",
3435
"phpunit/phpunit": "^13.2",
3536
"slevomat/coding-standard": "^8.31",
@@ -73,7 +74,7 @@
7374
"test-file": "@php ./vendor/bin/phpunit --configuration phpunit.xml --no-coverage --filter",
7475
"tests": [
7576
"@php -d memory_limit=2G ./vendor/bin/phpunit --configuration phpunit.xml tests",
76-
"@php ./vendor/bin/infection --threads=max --logger-html=reports/coverage/mutation-report.html --coverage=reports/coverage"
77+
"@php ./vendor/bin/infection --threads=max --logger-html=reports/coverage/mutation-report.html"
7778
]
7879
}
7980
}

‎phpstan.neon.dist‎

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,61 +5,60 @@ parameters:
55
- tests
66
tmpDir: reports/phpstan
77
ignoreErrors:
8-
# Late static binding in extension-point container factories that consumers subclass.
9-
- identifier: new.static
10-
paths:
11-
- src/FlywayDockerContainer.php
12-
- src/GenericDockerContainer.php
13-
- src/MySQLDockerContainer.php
148
# tiny-blocks/collection generics carry a mixed TValue on Internal command and definition types.
159
- identifier: missingType.generics
1610
paths:
1711
- src/Internal/Commands/DockerExecute.php
18-
- src/Internal/Containers/ContainerInspection.php
19-
- src/Internal/Commands/DockerRun.php
20-
- src/Internal/Containers/Address/Ports.php
12+
- src/Internal/Commands/DockerCreate.php
13+
- src/Internal/Containers/ContainerWaits.php
2114
- src/Internal/Containers/Definitions/ContainerDefinition.php
2215
- src/Internal/Containers/Environment/EnvironmentVariables.php
2316
# Internal collaborators take raw config arrays at the boundary, where PHPDoc is prohibited.
2417
- identifier: missingType.iterableValue
2518
paths:
19+
- src/Internal/Containers/ContainerLauncher.php
20+
- src/Internal/Containers/OneShotContainer.php
21+
- src/Internal/Containers/Drivers/MySQL/MySQLStartup.php
2622
- src/Internal/Commands/DockerExecute.php
27-
- src/Internal/Commands/DockerRun.php
23+
- src/Internal/Commands/DockerCreate.php
2824
- src/Internal/Containers/Address/Ports.php
2925
- src/Internal/Containers/ContainerInspection.php
26+
- src/Internal/Containers/Definitions/ContainerDefinition.php
3027
- src/Internal/Containers/Definitions/CopyInstruction.php
31-
- src/Internal/Containers/Definitions/EnvironmentVariable.php
32-
- src/Internal/Containers/Definitions/PortMapping.php
33-
- src/Internal/Containers/Definitions/VolumeMapping.php
28+
- src/Internal/Containers/Drivers/MySQL/JdbcUrl.php
3429
- src/Internal/Containers/Drivers/MySQL/MySQLCommands.php
3530
- src/Internal/Containers/Environment/EnvironmentVariables.php
3631
# Internal command builders return argument lists assembled from collection mixed values.
3732
- identifier: return.type
3833
paths:
3934
- src/Internal/Commands/DockerCopy.php
4035
- src/Internal/Commands/DockerExecute.php
41-
- src/Internal/Commands/DockerRun.php
36+
- src/Internal/Commands/DockerCreate.php
4237
- src/Internal/Containers/Address/Ports.php
4338
# Collection each/reduce pass concrete closures against the mixed-typed variadic API.
4439
- identifier: argument.type
4540
paths:
46-
- src/Internal/CommandHandler/ContainerCommandHandler.php
47-
- src/Internal/Commands/DockerRun.php
41+
- src/Internal/Containers/ContainerLauncher.php
42+
- src/Internal/Containers/ContainerWaits.php
4843
- src/Internal/Containers/Address/Ports.php
44+
- src/Internal/Containers/Definitions/ContainerDefinition.php
45+
# ContainerSharing starts a new container through a plain Closure, whose result is mixed to phpstan.
46+
- identifier: argument.type
47+
path: src/Internal/Containers/ContainerSharing.php
4948
# docker inspect json_decode and sprintf feed mixed values across the system boundary.
5049
- identifier: argument.type
5150
paths:
5251
- src/Internal/Containers/ContainerInspection.php
5352
- src/Internal/Containers/Drivers/MySQL/MySQLCommands.php
54-
# gethostname() returns string|false at the system boundary when the host name is unavailable.
53+
# MySQLCommands assembles the setup argument list as a raw array, where PHPDoc is prohibited.
5554
- identifier: argument.type
56-
path: src/Internal/Containers/ContainerReaper.php
55+
path: src/Internal/Containers/Drivers/MySQL/MySQLStartup.php
5756
# docker inspect json_decode produces mixed offsets read in ContainerInspection.
5857
- identifier: offsetAccess.nonOffsetAccessible
5958
path: src/Internal/Containers/ContainerInspection.php
60-
# docker inspect json_decode yields a mixed value cast to int at the boundary.
59+
# docker inspect json_decode yields a mixed port binding cast to int at the boundary.
6160
- identifier: cast.int
62-
path: src/Internal/Containers/ContainerInspection.php
61+
path: src/Internal/Containers/Address/Ports.php
6362
# docker inspect json_decode yields a mixed value iterated at the boundary.
6463
- identifier: foreach.nonIterable
6564
path: src/Internal/Containers/ContainerInspection.php
@@ -79,15 +78,28 @@ parameters:
7978
- tests/Unit/FlywayDockerContainerTest.php
8079
- tests/Unit/GenericDockerContainerTest.php
8180
- tests/Unit/MySQLDockerContainerTest.php
82-
# ClientMock's match arms assemble output tuples from untyped recorded responses.
83-
- identifier: return.type
81+
# ClientMock destructures the untyped response tuple it answers a command with.
82+
- identifier: offsetAccess.nonArray
83+
path: tests/Unit/ClientMock.php
84+
# ClientMock queues untyped response tuples under the command each one answers.
85+
- identifier: offsetAccess.nonOffsetAccessible
8486
path: tests/Unit/ClientMock.php
8587
# ClientMock casts a mixed recorded value to string when building command output.
8688
- identifier: cast.string
8789
path: tests/Unit/ClientMock.php
88-
# ClientMock indexes into a mixed recorded payload when replaying responses.
89-
- identifier: offsetAccess.nonArray
90-
path: tests/Unit/ClientMock.php
90+
# Tests index into the untyped argument lists the ClientMock records.
91+
- identifier: offsetAccess.nonOffsetAccessible
92+
paths:
93+
- tests/Unit/FlywayDockerContainerTest.php
94+
- tests/Unit/GenericDockerContainerTest.php
95+
# The shutdown spy records callbacks in an untyped global the test then invokes.
96+
- identifier: callable.nonCallable
97+
path: tests/Unit/GenericDockerContainerTest.php
98+
# Immutability tests discard the copy a with* method returns, to show the receiver is untouched.
99+
- identifier: method.resultUnused
100+
paths:
101+
- tests/Unit/FlywayDockerContainerTest.php
102+
- tests/Unit/MySQLDockerContainerTest.php
91103
# MySQLRepository reads a mixed PDO result as an object at the system boundary.
92104
- identifier: method.nonObject
93105
path: tests/Integration/MySQLRepository.php

‎src/ContainerStarted.php‎

Lines changed: 11 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,27 @@
44

55
namespace TinyBlocks\DockerContainer;
66

7-
use TinyBlocks\DockerContainer\Internal\Exceptions\DockerCommandExecutionFailed;
8-
use TinyBlocks\DockerContainer\Internal\Exceptions\StopTimeoutOutOfRange;
7+
use TinyBlocks\DockerContainer\Exceptions\DockerCommandExecutionFailed;
8+
use TinyBlocks\Time\Duration;
99

1010
/**
1111
* Represents a Docker container that has been started and is running.
12+
*
13+
* <p>A container this process started on its own is a {@see DisposableContainer}, which it may remove. A container
14+
* shared among processes is a {@see SharedContainer}, which tells whether it was reused.</p>
1215
*/
1316
interface ContainerStarted
1417
{
15-
/**
16-
* Default graceful period in whole seconds used when stopping the container.
17-
*
18-
* <p>After this period elapses, Docker forces the container to stop with SIGKILL.</p>
19-
*/
20-
public const int DEFAULT_TIMEOUT_IN_WHOLE_SECONDS = 10;
21-
2218
/**
2319
* Stops the running container gracefully.
2420
*
25-
* @param int $timeoutInWholeSeconds The graceful period in seconds to wait before forcing the stop.
21+
* <p>Docker forces the stop with SIGKILL once the grace period elapses.</p>
22+
*
23+
* @param Duration $gracePeriod The time to wait before forcing the stop.
2624
* @return ExecutionCompleted The result of the stop command execution.
27-
* @throws StopTimeoutOutOfRange If the timeout in whole seconds is negative.
28-
* @throws DockerCommandExecutionFailed If the stop command fails.
25+
* @throws DockerCommandExecutionFailed If the stop command cannot run.
2926
*/
30-
public function stop(int $timeoutInWholeSeconds = self::DEFAULT_TIMEOUT_IN_WHOLE_SECONDS): ExecutionCompleted;
27+
public function stop(Duration $gracePeriod): ExecutionCompleted;
3128

3229
/**
3330
* Returns the unique identifier of the container.
@@ -36,44 +33,26 @@ public function stop(int $timeoutInWholeSeconds = self::DEFAULT_TIMEOUT_IN_WHOLE
3633
*/
3734
public function getId(): string;
3835

39-
/**
40-
* Forcefully removes the container and its anonymous volumes, then prunes
41-
* unused networks created by the library.
42-
*/
43-
public function remove(): void;
44-
4536
/**
4637
* Returns the name assigned to the container.
4738
*
4839
* @return string The container name.
4940
*/
5041
public function getName(): string;
5142

52-
/**
53-
* Tells whether the container was reused from an already-running instance.
54-
*
55-
* @return bool True when an existing container was reused, false when a new one was started.
56-
*/
57-
public function wasReused(): bool;
58-
5943
/**
6044
* Returns the network address of the container.
6145
*
6246
* @return Address The container's network address.
6347
*/
6448
public function getAddress(): Address;
6549

66-
/**
67-
* Registers the container to be removed when the PHP process exits.
68-
*/
69-
public function stopOnShutdown(): void;
70-
7150
/**
7251
* Executes commands inside the running container.
7352
*
7453
* @param array<int, string> $commands The commands to execute inside the container.
7554
* @return ExecutionCompleted The result of the command execution.
76-
* @throws DockerCommandExecutionFailed If the command execution fails.
55+
* @throws DockerCommandExecutionFailed If the command execution cannot run.
7756
*/
7857
public function executeAfterStarted(array $commands): ExecutionCompleted;
7958

‎src/DisposableContainer.php‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TinyBlocks\DockerContainer;
6+
7+
use TinyBlocks\DockerContainer\Exceptions\DockerCommandExecutionFailed;
8+
9+
/**
10+
* A started container this process owns alone, so it may remove the container once done with it.
11+
*/
12+
interface DisposableContainer extends ContainerStarted
13+
{
14+
/**
15+
* Forcefully removes the container and its anonymous volumes, then prunes the unused networks created by the
16+
* library.
17+
*
18+
* @throws DockerCommandExecutionFailed If a removal command cannot run.
19+
*/
20+
public function remove(): void;
21+
22+
/**
23+
* Registers the container to be removed when the PHP process exits.
24+
*/
25+
public function stopOnShutdown(): void;
26+
}

‎src/DockerClient.php‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TinyBlocks\DockerContainer;
6+
7+
use TinyBlocks\DockerContainer\Exceptions\DockerCommandExecutionFailed;
8+
9+
/**
10+
* Executes the Docker commands the library issues, the single boundary between the library and the Docker engine.
11+
*
12+
* <p>Every container factory defaults to a client that invokes the local <code>docker</code> executable. A custom
13+
* client replaces it, for example to route the commands to another Docker-compatible engine, or to stand in for
14+
* the engine in the unit tests of code that builds containers.</p>
15+
*/
16+
interface DockerClient
17+
{
18+
/**
19+
* Executes a Docker command within the default timeout of the client and returns its outcome.
20+
*
21+
* @param DockerCommand $command The Docker command to execute.
22+
* @return ExecutionCompleted The outcome of the command.
23+
* @throws DockerCommandExecutionFailed If the command cannot run or exceeds the default timeout.
24+
*/
25+
public function execute(DockerCommand $command): ExecutionCompleted;
26+
27+
/**
28+
* Executes a Docker command within the timeout the command carries and returns its outcome.
29+
*
30+
* @param DockerCommandWithTimeout $command The Docker command to execute.
31+
* @return ExecutionCompleted The outcome of the command.
32+
* @throws DockerCommandExecutionFailed If the command cannot run or exceeds its timeout.
33+
*/
34+
public function executeWithTimeout(DockerCommandWithTimeout $command): ExecutionCompleted;
35+
}

‎src/DockerCommand.php‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TinyBlocks\DockerContainer;
6+
7+
/**
8+
* A Docker command line the library issues through a {@see DockerClient}.
9+
*
10+
* <p>A command bounded by a timeout of its own is a {@see DockerCommandWithTimeout}. Any other command runs within
11+
* the default timeout of the client.</p>
12+
*/
13+
interface DockerCommand
14+
{
15+
/**
16+
* Returns the DockerCommand as an ordered argument list.
17+
*
18+
* <p>The first element is the executable and the remaining elements are its arguments. No shell interpretation
19+
* happens between elements, so values are passed through verbatim.</p>
20+
*
21+
* @return array<int, string> The ordered argument list.
22+
*/
23+
public function toArguments(): array;
24+
}

‎src/DockerCommandWithTimeout.php‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TinyBlocks\DockerContainer;
6+
7+
use TinyBlocks\Time\Duration;
8+
9+
/**
10+
* A Docker command that must finish within a timeout of its own, such as a container run until it exits.
11+
*/
12+
interface DockerCommandWithTimeout extends DockerCommand
13+
{
14+
/**
15+
* Returns the longest time the command may run before it is interrupted.
16+
*
17+
* @return Duration The timeout.
18+
*/
19+
public function timeout(): Duration;
20+
}

0 commit comments

Comments
 (0)