Skip to content

Commit a9e61d3

Browse files
committed
Add tests for docker:build and docker:push
1 parent 5bd39bf commit a9e61d3

14 files changed

+400
-39
lines changed

src/Commands/BaseCommand.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,15 @@ abstract class BaseCommand extends Command
88
{
99
private const NONE = 'none';
1010

11-
public function optionalChoice(string $question, array $choices, $default = null): string|false
11+
/**
12+
* Ask an optional question with a "none" option.
13+
*
14+
* @param string $question
15+
* @param string[] $choices
16+
* @param string|null $default
17+
* @return string|false
18+
*/
19+
public function optionalChoice(string $question, array $choices, string $default = null): string|false
1220
{
1321
$choice = $this->choice(
1422
question: $question,

src/Commands/BaseDockerCommand.php

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,23 @@
66

77
abstract class BaseDockerCommand extends BaseCommand
88
{
9-
protected function getEnvironment(): array
9+
public function getEnvironment(): array
1010
{
11+
/** @var \Illuminate\Config\Repository $config */
12+
$config = app('config');
13+
1114
return [
12-
'DOCKER_NGINX_TAG' => config('docker-builder.tags.nginx'),
13-
'DOCKER_PHP_TAG' => config('docker-builder.tags.php'),
15+
'DOCKER_NGINX_TAG' => $config->get('docker-builder.tags.nginx'),
16+
'DOCKER_PHP_TAG' => $config->get('docker-builder.tags.php'),
1417
];
1518
}
1619

17-
protected function runProcess(Process $process): int
20+
public function runProcess(Process $process, $out = STDOUT, $err = STDERR): int
1821
{
19-
return $process->run(function ($type, $buffer) {
22+
return $process->run(function ($type, $buffer) use ($out, $err) {
2023
match ($type) {
21-
Process::OUT => fwrite(STDOUT, $buffer),
22-
Process::ERR => fwrite(STDERR, $buffer),
24+
Process::OUT => fwrite($out, $buffer),
25+
Process::ERR => fwrite($err, $buffer),
2326
};
2427
});
2528
}

src/Commands/GenerateQuestions/PhpVersionQuestion.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ public function getAnswer(BaseCommand $command): string
2828

2929
$detected = app(PhpVersionDetector::class)->detect();
3030

31-
if ($command->option('detect')) {
32-
return $detected;
31+
if ($detected && $command->option('detect')) {
32+
return (string) $detected;
3333
}
3434

3535
return $command->choice(

src/Detector/FileDetector.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,8 @@ public function detect(): string|false
1515
return false;
1616
}
1717

18+
/**
19+
* @return array<string, string>
20+
*/
1821
abstract protected function getPathMapping(): array;
1922
}

src/Detector/PhpExtensionsDetector.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77

88
class PhpExtensionsDetector implements DetectorContract
99
{
10+
/**
11+
* @param string[] $supportedExtensions
12+
*/
1013
public function __construct(private array $supportedExtensions)
1114
{
1215
}
@@ -32,11 +35,17 @@ public function detect(): string|false
3235
->join(',');
3336
}
3437

38+
/**
39+
* @return string[]
40+
*/
3541
private function getDefaultExtensions(): array
3642
{
3743
return ['bcmath'];
3844
}
3945

46+
/**
47+
* @return string[]
48+
*/
4049
private function getCacheExtensions(): array
4150
{
4251
$store = config('cache.default');
@@ -50,6 +59,9 @@ private function getCacheExtensions(): array
5059
});
5160
}
5261

62+
/**
63+
* @return string[]
64+
*/
5365
public function getDatabaseExtensions(): array
5466
{
5567
$connection = config('database.default');
@@ -63,6 +75,9 @@ public function getDatabaseExtensions(): array
6375
});
6476
}
6577

78+
/**
79+
* @return string[]
80+
*/
6681
public function getBroadcastingExtensions(): array
6782
{
6883
$connection = config('broadcasting.default');
@@ -75,7 +90,7 @@ public function getBroadcastingExtensions(): array
7590
}
7691

7792
/**
78-
* @return array
93+
* @return string[]
7994
*/
8095
public function getQueueExtensions(): array
8196
{
@@ -89,7 +104,7 @@ public function getQueueExtensions(): array
89104
}
90105

91106
/**
92-
* @return array
107+
* @return string[]
93108
*/
94109
public function getSessionExtensions(): array
95110
{

src/Detector/PhpVersionDetector.php

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,32 +12,26 @@ class PhpVersionDetector implements DetectorContract
1212
public function detect(): string|false
1313
{
1414
$composer = file_get_contents(base_path('composer.json'));
15-
$composer = json_decode($composer);
16-
$php = $composer?->require?->php;
17-
18-
if (is_string($php)) {
19-
$parser = new VersionParser();
20-
$php = $parser->parseConstraints($php)
21-
->getLowerBound()
22-
->getVersion();
23-
24-
return Arr::first(
25-
array: PhpVersion::values(),
26-
callback: fn ($value) => Str::startsWith($php, $value),
27-
default: false,
28-
);
15+
if (! $composer) {
16+
return false;
2917
}
3018

31-
preg_match(
32-
pattern: '/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/',
33-
subject: $php,
34-
matches: $matches,
35-
);
19+
$composer = json_decode($composer);
20+
$php = data_get($composer, 'require.php');
3621

37-
if (empty($matches)) {
22+
if (! is_string($php)) {
3823
return false;
3924
}
4025

41-
return false;
26+
$parser = new VersionParser();
27+
$php = $parser->parseConstraints($php)
28+
->getLowerBound()
29+
->getVersion();
30+
31+
return Arr::first(
32+
array: PhpVersion::values(),
33+
callback: fn ($value) => Str::startsWith($php, $value),
34+
default: false,
35+
);
4236
}
4337
}

src/Objects/Configuration.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44

55
class Configuration
66
{
7+
/**
8+
* @param string $phpVersion
9+
* @param string[] $phpExtensions
10+
* @param bool $artisanOptimize
11+
* @param string|false $nodePackageManager
12+
* @param string|false $nodeBuildTool
13+
*/
714
public function __construct(
815
private string $phpVersion,
916
private array $phpExtensions,
@@ -18,6 +25,9 @@ public function getPhpVersion(): string
1825
return $this->phpVersion;
1926
}
2027

28+
/**
29+
* @return string[]
30+
*/
2131
public function getPhpExtensions(): array
2232
{
2333
return $this->phpExtensions;
@@ -38,16 +48,19 @@ public function getNodeBuildTool(): string|false
3848
return $this->nodeBuildTool;
3949
}
4050

51+
/**
52+
* @return string[]
53+
*/
4154
public function getCommand(): array
4255
{
43-
return array_filter([
56+
return array_values(array_filter([
4457
'php', 'artisan', 'docker:generate',
4558
'-n', // --no-interaction
4659
'-p '.$this->getPhpVersion(), // --php-version
4760
'-e '.implode(',', $this->getPhpExtensions()), // --php-extensions
4861
$this->isArtisanOptimize() ? '-o' : null, // --optimize
4962
$this->getNodePackageManager() ? '-m '.$this->getNodePackageManager() : null, // --node-package-manager
5063
$this->getNodePackageManager() ? '-b '.$this->getNodeBuildTool() : null, // --node-build-tool
51-
]);
64+
]));
5265
}
5366
}

src/Traits/InteractsWithTwig.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
namespace BlameButton\LaravelDockerBuilder\Traits;
44

5+
use RuntimeException;
56
use Twig\Environment as TwigEnvironment;
7+
use Twig\Error\Error;
68
use Twig\Loader\FilesystemLoader;
79

810
trait InteractsWithTwig
@@ -14,14 +16,26 @@ private function twig(): TwigEnvironment
1416
if (! is_null($this->twig)) {
1517
return $this->twig;
1618
}
19+
1720
$path = package_path('docker/template');
1821
$loader = new FilesystemLoader($path);
1922

2023
return $this->twig = new TwigEnvironment($loader);
2124
}
2225

26+
/**
27+
* Render a Twig template.
28+
*
29+
* @param string $name
30+
* @param array<string, mixed> $context
31+
* @return string
32+
*/
2333
private function render(string $name, array $context): string
2434
{
25-
return $this->twig()->render($name, $context);
35+
try {
36+
return $this->twig()->render($name, $context);
37+
} catch (Error $error) {
38+
throw new RuntimeException($error->getMessage());
39+
}
2640
}
2741
}

src/helpers.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ function package_path(string $path = null): string
55
{
66
$dir = dirname(__FILE__, 2);
77

8-
if ($path = str($path)->ltrim(DIRECTORY_SEPARATOR)) {
8+
if (! is_null($path) && $path = ltrim($path, DIRECTORY_SEPARATOR)) {
99
return $dir.DIRECTORY_SEPARATOR.$path;
1010
}
1111

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
namespace BlameButton\LaravelDockerBuilder\Tests\Commands;
4+
5+
use BlameButton\LaravelDockerBuilder\Commands\BaseDockerCommand;
6+
use BlameButton\LaravelDockerBuilder\Tests\TestCase;
7+
use Mockery\MockInterface;
8+
use Symfony\Component\Process\Process;
9+
10+
/**
11+
* @uses \BlameButton\LaravelDockerBuilder\DockerServiceProvider
12+
*
13+
* @covers \BlameButton\LaravelDockerBuilder\Commands\BaseDockerCommand
14+
*/
15+
class BaseDockerCommandTest extends TestCase
16+
{
17+
public function testItUsesConfigurationValues(): void
18+
{
19+
$this->mock('config', function (MockInterface $mock) {
20+
$mock->shouldReceive('get')
21+
->once()
22+
->with('docker-builder.tags.nginx')
23+
->andReturn('test:nginx');
24+
$mock->shouldReceive('get')
25+
->once()
26+
->with('docker-builder.tags.php')
27+
->andReturn('test:php');
28+
});
29+
30+
$class = $this->newBaseDockerCommand();
31+
$environment = $class->getEnvironment();
32+
33+
self::assertEquals([
34+
'DOCKER_NGINX_TAG' => 'test:nginx',
35+
'DOCKER_PHP_TAG' => 'test:php',
36+
], $environment);
37+
}
38+
39+
public function testItRunsProcess(): void
40+
{
41+
$mock = $this->createMock(Process::class);
42+
$mock->expects($this->once())
43+
->method('run')
44+
->willReturnCallback(function ($callable) {
45+
$callable(Process::OUT, "stdout output\n");
46+
$callable(Process::ERR, "stderr output\n");
47+
48+
return 0;
49+
});
50+
51+
$class = $this->newBaseDockerCommand();
52+
$output = $class->runProcess(
53+
process: $mock,
54+
out: fopen('php://memory', 'r+'),
55+
err: fopen('php://memory', 'r+'),
56+
);
57+
58+
self::assertEquals(0, $output);
59+
}
60+
61+
private function newBaseDockerCommand(): BaseDockerCommand
62+
{
63+
return new class extends BaseDockerCommand
64+
{
65+
};
66+
}
67+
}

0 commit comments

Comments
 (0)