Skip to content
Merged
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
22 changes: 22 additions & 0 deletions .github/workflows/code-style.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Check code style

on: [push]

jobs:
code-style:
runs-on: ubuntu-latest
name: Code style
steps:
- name: Checkout code
uses: actions/checkout@v7

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.2

- name: Install
run: composer install --prefer-dist --no-interaction

- name: Code style checks for PHP
run: composer cs
32 changes: 32 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Execute tests

on: [push]

jobs:
tests:
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
php: [8.2,8.3,8.4,8.5]

name: Tests

steps:
- name: Checkout code
uses: actions/checkout@v7

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}

- name: Install
run: composer install --prefer-dist --no-interaction

- name: Run unit tests
run: composer test

- name: Run integration tests against Docker
run: composer test:integration
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ composer.lock
.phpunit.result.cache
.phpstan.cache/
.idea/
.php-cs-fixer.cache
45 changes: 45 additions & 0 deletions .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

use PhpCsFixer\Config;
use PhpCsFixer\Finder;

return (new Config())
->setRiskyAllowed(false)
->setRules([
'array_syntax' => [ 'syntax' => 'short' ],
'binary_operator_spaces' => true,
'cast_spaces' => false,
'combine_consecutive_unsets' => true,
'concat_space' => [ 'spacing' => 'one' ],
'linebreak_after_opening_tag' => true,
'no_blank_lines_after_class_opening' => true,
'no_blank_lines_after_phpdoc' => true,
'no_extra_blank_lines' => true,
'no_trailing_comma_in_singleline_array' => false,
'no_whitespace_in_blank_line' => true,
'no_spaces_around_offset' => true,
'no_unused_imports' => true,
'no_useless_else' => true,
'no_useless_return' => true,
'no_whitespace_before_comma_in_array' => true,
'normalize_index_brace' => true,
'phpdoc_indent' => true,
'phpdoc_to_comment' => false,
'phpdoc_trim' => true,
'single_quote' => true,
'ternary_operator_spaces' => true,
'ternary_to_null_coalescing' => true,
'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'],
'no_break_comment' => false,
'blank_line_before_statement' => false,
'line_ending' => true,
'single_blank_line_at_eof' => true,
'short_scalar_cast' => true,
'fully_qualified_strict_types' => true,
'no_superfluous_phpdoc_tags' => true,
'no_empty_phpdoc' => true
])
->setFinder((new Finder())->in(__DIR__))
;
30 changes: 15 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ $docker->volumes()->remove('my-volume');
## Typed results

`list()` and `inspect()` on Containers, Images, Networks and Volumes return
typed DTOs not raw JSON so you get autocompletion and don't have to
typed DTOs - not raw JSON - so you get autocompletion and don't have to
remember Docker's field names:

```php
Expand All @@ -78,7 +78,7 @@ $image = $docker->images()->inspect('nginx:latest');
echo $image->getName(); // "nginx:latest" (first RepoTag), or null if untagged

foreach ($docker->containers()->list(['all' => true]) as $summary) {
echo $summary->getName(), ' ', $summary->status, "\n";
echo $summary->getName(), ' - ', $summary->status, "\n";
}
```

Expand All @@ -92,11 +92,11 @@ foreach ($docker->containers()->list(['all' => true]) as $summary) {
| `volumes()->list()` / `inspect()` | `list<DTO\VolumeInfo>` / `DTO\VolumeInfo` |

Every DTO only models the commonly-needed fields (id, name, state, labels,
...) call `->raw()` on any of them to get the full, untouched decoded
...) - call `->raw()` on any of them to get the full, untouched decoded
array for anything not promoted to a typed property.

Every other resource method (`start()`, `stop()`, `remove()`, `create()`,
...) still returns a `Sytxlabs\Dockphp\Http\DockerResponse` there's no
...) still returns a `Sytxlabs\Dockphp\Http\DockerResponse` - there's no
useful entity to hydrate from an action's ack/204 response. Use `->json()`
for the decoded body or `->getBody()` for the raw string.

Expand All @@ -105,7 +105,7 @@ for the decoded body or `->getBody()` for the raw string.
`containers()->create()` accepts the full Docker container config as a
single array. Query-only parameters (`name`, `platform`) are automatically
split out of the array and sent as query string parameters, the rest is
sent as the JSON request body you never have to think about the split:
sent as the JSON request body - you never have to think about the split:

```php
$container = $docker->containers()->create([
Expand Down Expand Up @@ -137,7 +137,7 @@ $docker->volumes()->create('my-volume', ['Driver' => 'local']);
## API version handling

By default, the API version is **not** fetched eagerly when you construct
`DockerClient` it is resolved lazily via a single `GET /version` call the
`DockerClient` - it is resolved lazily via a single `GET /version` call the
first time a request is made, then cached for the lifetime of the client.

You can override it manually to skip that lookup entirely and pin a
Expand All @@ -159,12 +159,12 @@ $docker = new DockerClient(

## Error handling

- `Sytxlabs\Dockphp\Exceptions\DockerConnectionException` the socket
- `Sytxlabs\Dockphp\Exceptions\DockerConnectionException` - the socket
could not be reached at all (missing socket, connection refused, timeout).
- `Sytxlabs\Dockphp\Exceptions\DockerApiException` the Engine responded
- `Sytxlabs\Dockphp\Exceptions\DockerApiException` - the Engine responded
with a non-2xx HTTP status. Carries `getStatusCode()` and
`getDockerMessage()` (Docker's own JSON error message, when present).
- `Sytxlabs\Dockphp\Exceptions\DockerNotFoundException` a `DockerApiException`
- `Sytxlabs\Dockphp\Exceptions\DockerNotFoundException` - a `DockerApiException`
subclass specifically for HTTP 404 (e.g. inspecting a container that
doesn't exist).

Expand All @@ -190,7 +190,7 @@ try {

The Docker Engine API, reached through `/var/run/docker.sock`, grants
practically full control over the Docker host. **This package never
changes socket permissions itself** (no `chmod`, no ownership changes)
changes socket permissions itself** (no `chmod`, no ownership changes) -
managing who can read/write that socket is entirely up to you and your
deployment. Only grant access to the socket to trusted, trusted-equivalent
code.
Expand All @@ -210,7 +210,7 @@ $docker->containers()->logsStream('web', function (string $chunk) {

// Live stats
$docker->containers()->statsStream('web', function (string $chunk) {
// one or more JSON objects per chunk see NdjsonLineBuffer below
// one or more JSON objects per chunk - see NdjsonLineBuffer below
});

// Pull with progress
Expand All @@ -231,7 +231,7 @@ $docker->system()->events(function (array $event) {

`pullStream()`/`buildStream()`/`events()` already decode newline-delimited
JSON for you via `Sytxlabs\Dockphp\Support\NdjsonLineBuffer`. `logsStream()`
and `attachStream()` hand you raw bytes instead see the demux section
and `attachStream()` hand you raw bytes instead - see the demux section
below.

## Demultiplexing container logs
Expand Down Expand Up @@ -293,7 +293,7 @@ $docker = DockerClient::tcp('docker.example.com', 2376, tls: true, caFile: '/pat
## Registry authentication (pull/push)

`pull()`, `pullStream()`, `push()` and `pushStream()` take an optional
`$registryAuth` array the usual Docker auth config
`$registryAuth` array - the usual Docker auth config
(`username`/`password`/`serveraddress`, or `identitytoken`). It's sent as
the base64-encoded `X-Registry-Auth` header Docker expects:

Expand Down Expand Up @@ -322,8 +322,8 @@ composer stan # static analysis (PHPStan)

Integration tests automatically skip themselves when
`/var/run/docker.sock` is not present (e.g. on Windows, or a machine
without Docker installed) no configuration required.
without Docker installed) - no configuration required.

## License

MIT see [LICENSE](LICENSE).
MIT - see [LICENSE](LICENSE).
6 changes: 4 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
},
"require-dev": {
"phpunit/phpunit": "^11.0",
"phpstan/phpstan": "^1.11"
"phpstan/phpstan": "^1.11",
"friendsofphp/php-cs-fixer": "^3.15"
},
"autoload": {
"psr-4": {
Expand All @@ -32,7 +33,8 @@
"scripts": {
"test": "phpunit --testsuite Unit",
"test:integration": "phpunit --testsuite Integration",
"stan": "phpstan analyse"
"cs": "phpstan analyse",
"csfix": "php-cs-fixer fix"
},
"minimum-stability": "stable",
"prefer-stable": true
Expand Down
23 changes: 11 additions & 12 deletions src/DTO/ContainerInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*
* @see https://docs.docker.com/engine/api/latest/#tag/Container/operation/ContainerInspect
*/
final class ContainerInfo
final readonly class ContainerInfo
{
/**
* @param list<string> $args
Expand All @@ -18,17 +18,16 @@ final class ContainerInfo
* @param array<string, mixed> $raw The untouched, fully decoded source array.
*/
public function __construct(
public readonly string $id,
public readonly string $name,
public readonly string $image,
public readonly string $path,
public readonly array $args,
public readonly array $state,
public readonly array $config,
public readonly string $created,
private readonly array $raw,
) {
}
public string $id,
public string $name,
public string $image,
public string $path,
public array $args,
public array $state,
public array $config,
public string $created,
private array $raw,
) {}

/**
* @param array<string, mixed> $data
Expand Down
25 changes: 12 additions & 13 deletions src/DTO/ContainerSummary.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,25 @@
*
* @see https://docs.docker.com/engine/api/latest/#tag/Container/operation/ContainerList
*/
final class ContainerSummary
final readonly class ContainerSummary
{
/**
* @param list<string> $names Docker's own names, each still prefixed with a leading "/".
* @param array<string, string> $labels
* @param array<string, mixed> $raw The untouched, fully decoded source array.
*/
public function __construct(
public readonly string $id,
public readonly array $names,
public readonly string $image,
public readonly string $imageId,
public readonly string $command,
public readonly int $created,
public readonly string $state,
public readonly string $status,
public readonly array $labels,
private readonly array $raw,
) {
}
public string $id,
public array $names,
public string $image,
public string $imageId,
public string $command,
public int $created,
public string $state,
public string $status,
public array $labels,
private array $raw,
) {}

/**
* @param array<string, mixed> $data
Expand Down
29 changes: 14 additions & 15 deletions src/DTO/ImageInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*
* @see https://docs.docker.com/engine/api/latest/#tag/Image/operation/ImageInspect
*/
final class ImageInfo
final readonly class ImageInfo
{
/**
* @param list<string> $repoTags Empty when the image is untagged.
Expand All @@ -18,20 +18,19 @@ final class ImageInfo
* @param array<string, mixed> $raw The untouched, fully decoded source array.
*/
public function __construct(
public readonly string $id,
public readonly array $repoTags,
public readonly array $repoDigests,
public readonly string $parent,
public readonly string $comment,
public readonly string $created,
public readonly string $author,
public readonly string $architecture,
public readonly string $os,
public readonly int $size,
public readonly array $config,
private readonly array $raw,
) {
}
public string $id,
public array $repoTags,
public array $repoDigests,
public string $parent,
public string $comment,
public string $created,
public string $author,
public string $architecture,
public string $os,
public int $size,
public array $config,
private array $raw,
) {}

/**
* @param array<string, mixed> $data
Expand Down
21 changes: 10 additions & 11 deletions src/DTO/ImageSummary.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*
* @see https://docs.docker.com/engine/api/latest/#tag/Image/operation/ImageList
*/
final class ImageSummary
final readonly class ImageSummary
{
/**
* @param list<string> $repoTags Empty when the image is untagged (`<none>:<none>`).
Expand All @@ -18,16 +18,15 @@ final class ImageSummary
* @param array<string, mixed> $raw The untouched, fully decoded source array.
*/
public function __construct(
public readonly string $id,
public readonly string $parentId,
public readonly array $repoTags,
public readonly array $repoDigests,
public readonly int $created,
public readonly int $size,
public readonly array $labels,
private readonly array $raw,
) {
}
public string $id,
public string $parentId,
public array $repoTags,
public array $repoDigests,
public int $created,
public int $size,
public array $labels,
private array $raw,
) {}

/**
* @param array<string, mixed> $data
Expand Down
Loading