Skip to content

Commit 308b13a

Browse files
MAGECLOUD-2626: Create Wrapper for Running bin/magento (#349)
1 parent c2ea18d commit 308b13a

File tree

16 files changed

+376
-96
lines changed

16 files changed

+376
-96
lines changed

src/Config/Environment.php

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -251,14 +251,6 @@ public function getCryptKey(): string
251251
return $this->getVariable('CRYPT_KEY', '');
252252
}
253253

254-
/**
255-
* @return string
256-
*/
257-
public function getMinLoggingLevel(): string
258-
{
259-
return $this->getVariable('MIN_LOGGING_LEVEL', '');
260-
}
261-
262254
/**
263255
* Checks that environment uses the main branch depending on environment variable MAGENTO_CLOUD_ENVIRONMENT
264256
* which contains the name of the git branch.

src/Config/Magento/System.php

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,30 @@
99

1010
use Magento\MagentoCloud\Package\MagentoVersion;
1111
use Magento\MagentoCloud\Package\UndefinedPackageException;
12-
use Magento\MagentoCloud\Shell\ShellInterface;
12+
use Magento\MagentoCloud\Shell\ShellFactory;
1313

1414
/**
1515
* Retrieves a value by running bin/magento config:show
1616
*/
1717
class System
1818
{
1919
/**
20-
* @var ShellInterface
20+
* @var ShellFactory
2121
*/
22-
private $shell;
22+
private $shellFactory;
2323

2424
/**
2525
* @var MagentoVersion
2626
*/
2727
private $magentoVersion;
2828

2929
/**
30-
* @param ShellInterface $shell
30+
* @param ShellFactory $shellFactory
3131
* @param MagentoVersion $magentoVersion
3232
*/
33-
public function __construct(ShellInterface $shell, MagentoVersion $magentoVersion)
33+
public function __construct(ShellFactory $shellFactory, MagentoVersion $magentoVersion)
3434
{
35-
$this->shell = $shell;
35+
$this->shellFactory = $shellFactory;
3636
$this->magentoVersion = $magentoVersion;
3737
}
3838

@@ -50,15 +50,9 @@ public function get(string $key)
5050
return null;
5151
}
5252

53-
try {
54-
$result = implode(PHP_EOL, $this->shell->execute(sprintf(
55-
'php ./bin/magento config:show %s',
56-
escapeshellarg($key)
57-
)));
58-
} catch (\Exception $e) {
59-
return null;
60-
}
61-
62-
return $result;
53+
return implode(PHP_EOL, $this->shellFactory->create(ShellFactory::STRATEGY_MAGENTO_SHELL)->execute(
54+
'config:show',
55+
$key
56+
));
6357
}
6458
}

src/Shell/MagentoShell.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\MagentoCloud\Shell;
9+
10+
/**
11+
* ./bin/magento shell wrapper.
12+
*/
13+
class MagentoShell implements ShellInterface
14+
{
15+
/**
16+
* @var Shell
17+
*/
18+
private $shell;
19+
20+
/**
21+
* @param Shell $shell
22+
*/
23+
public function __construct(Shell $shell)
24+
{
25+
$this->shell = $shell;
26+
}
27+
28+
/**
29+
* @inheritdoc
30+
*/
31+
public function execute(string $command, $args = []): array
32+
{
33+
$defaultArgs = ['--ansi', '--no-interaction'];
34+
35+
return $this->shell->execute('php ./bin/magento ' . $command, array_merge($defaultArgs, (array)$args));
36+
}
37+
}

src/Shell/Shell.php

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
declare(strict_types=1);
7+
68
namespace Magento\MagentoCloud\Shell;
79

8-
use Magento\MagentoCloud\Filesystem\DirectoryList;
10+
use Magento\MagentoCloud\Filesystem\SystemList;
911
use Psr\Log\LoggerInterface;
1012
use Monolog\Logger;
1113

@@ -20,18 +22,18 @@ class Shell implements ShellInterface
2022
private $logger;
2123

2224
/**
23-
* @var DirectoryList
25+
* @var SystemList
2426
*/
25-
private $directoryList;
27+
private $systemList;
2628

2729
/**
2830
* @param LoggerInterface $logger
29-
* @param DirectoryList $directoryList
31+
* @param SystemList $systemList
3032
*/
31-
public function __construct(LoggerInterface $logger, DirectoryList $directoryList)
33+
public function __construct(LoggerInterface $logger, SystemList $systemList)
3234
{
3335
$this->logger = $logger;
34-
$this->directoryList = $directoryList;
36+
$this->systemList = $systemList;
3537
}
3638

3739
/**
@@ -43,18 +45,47 @@ public function __construct(LoggerInterface $logger, DirectoryList $directoryLis
4345
* $this->shell->execute('/bin/bash -c "set -o pipefail; firstCommand | secondCommand"');
4446
* ```
4547
*/
46-
public function execute(string $command)
48+
public function execute(string $command, $args = []): array
4749
{
50+
$args = array_map(
51+
'escapeshellarg',
52+
array_filter((array)$args)
53+
);
54+
55+
if ($args) {
56+
$command .= ' ' . implode(' ', $args);
57+
}
58+
4859
$this->logger->info($command);
4960

50-
$rootPathCommand = sprintf(
61+
$fullCommand = sprintf(
5162
'cd %s && %s 2>&1',
52-
$this->directoryList->getMagentoRoot(),
63+
$this->systemList->getMagentoRoot(),
5364
$command
5465
);
5566

56-
exec($rootPathCommand, $output, $status);
67+
exec($fullCommand, $output, $status);
68+
69+
/**
70+
* config:show will return non-zero exit code, if the value was not changed and remains default.
71+
*/
72+
if ($status !== 0 && strpos($command, 'config:show') !== false) {
73+
return [];
74+
}
5775

76+
return $this->handleOutput($command, $output, $status);
77+
}
78+
79+
/**
80+
* @param string $command
81+
* @param array $output
82+
* @param int $status
83+
* @return array
84+
*
85+
* @throws ShellException
86+
*/
87+
private function handleOutput(string $command, array $output, int $status): array
88+
{
5889
if ($output) {
5990
$message = array_reduce(
6091
$output,
@@ -64,11 +95,11 @@ function ($message, $line) {
6495
''
6596
);
6697

67-
$this->logger->log($status != 0 ? Logger::CRITICAL : Logger::DEBUG, $message);
98+
$this->logger->log($status !== 0 ? Logger::CRITICAL : Logger::DEBUG, $message);
6899
}
69100

70-
if ($status != 0) {
71-
throw new \RuntimeException("Command $command returned code $status", $status);
101+
if ($status !== 0) {
102+
throw new ShellException("Command $command returned code $status", $status);
72103
}
73104

74105
return $output;

src/Shell/ShellException.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\MagentoCloud\Shell;
7+
8+
/**
9+
* Exception for shell operations.
10+
*/
11+
class ShellException extends \RuntimeException
12+
{
13+
}

src/Shell/ShellFactory.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\MagentoCloud\Shell;
9+
10+
use Magento\MagentoCloud\App\ContainerInterface;
11+
12+
/**
13+
* Factory class for shell wrappers.
14+
*/
15+
class ShellFactory
16+
{
17+
const STRATEGY_SHELL = 'shell';
18+
const STRATEGY_MAGENTO_SHELL = 'magento_shell';
19+
20+
/**
21+
* @var ContainerInterface
22+
*/
23+
private $container;
24+
25+
/**
26+
* @param ContainerInterface $container
27+
*/
28+
public function __construct(ContainerInterface $container)
29+
{
30+
$this->container = $container;
31+
}
32+
33+
/**
34+
* @param string $strategy
35+
* @return ShellInterface
36+
*/
37+
public function create(string $strategy): ShellInterface
38+
{
39+
if ($strategy === self::STRATEGY_MAGENTO_SHELL) {
40+
return $this->container->create(MagentoShell::class);
41+
}
42+
43+
return $this->container->create(Shell::class);
44+
}
45+
}

src/Shell/ShellInterface.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
declare(strict_types=1);
7+
68
namespace Magento\MagentoCloud\Shell;
79

810
/**
@@ -14,8 +16,9 @@ interface ShellInterface
1416
* Runs shell command.
1517
*
1618
* @param string $command The command.
19+
* @param string|array $args Arguments to pass
1720
* @return array The output of command.
18-
* @throws \RuntimeException If command was executed with error
21+
* @throws ShellException If command was executed with error
1922
*/
20-
public function execute(string $command);
23+
public function execute(string $command, $args = []): array;
2124
}

src/Test/Unit/Config/Magento/SystemTest.php

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Magento\MagentoCloud\Config\Magento\System;
1111
use Magento\MagentoCloud\Package\MagentoVersion;
1212
use Magento\MagentoCloud\Package\UndefinedPackageException;
13+
use Magento\MagentoCloud\Shell\ShellFactory;
1314
use Magento\MagentoCloud\Shell\ShellInterface;
1415
use PHPUnit\Framework\TestCase;
1516
use PHPUnit\Framework\MockObject\MockObject;
@@ -24,6 +25,11 @@ class SystemTest extends TestCase
2425
*/
2526
private $config;
2627

28+
/**
29+
* @var ShellFactory|MockObject
30+
*/
31+
private $shellFactoryMock;
32+
2733
/**
2834
* @var ShellInterface|MockObject
2935
*/
@@ -39,11 +45,16 @@ class SystemTest extends TestCase
3945
*/
4046
protected function setUp()
4147
{
42-
$this->shellMock = $this->getMockForAbstractClass(ShellInterface::class);
48+
$this->shellFactoryMock = $this->createMock(ShellFactory::class);
4349
$this->magentoVersionMock = $this->createMock(MagentoVersion::class);
50+
$this->shellMock = $this->getMockForAbstractClass(ShellInterface::class);
51+
52+
$this->shellFactoryMock->method('create')
53+
->with(ShellFactory::STRATEGY_MAGENTO_SHELL)
54+
->willReturn($this->shellMock);
4455

4556
$this->config = new System(
46-
$this->shellMock,
57+
$this->shellFactoryMock,
4758
$this->magentoVersionMock
4859
);
4960
}
@@ -61,7 +72,7 @@ public function testValidate($expectedResult)
6172
->willReturn(true);
6273
$this->shellMock->expects($this->once())
6374
->method('execute')
64-
->with('php ./bin/magento config:show \'some/key\'')
75+
->with('config:show', 'some/key')
6576
->willReturn([$expectedResult]);
6677

6778
$this->assertSame($expectedResult, $this->config->get('some/key'));
@@ -90,10 +101,10 @@ public function testGetDefaultValue()
90101
->willReturn(true);
91102
$this->shellMock->expects($this->once())
92103
->method('execute')
93-
->with('php ./bin/magento config:show \'some/key\'')
94-
->willThrowException(new \Exception('Command bin/magento returned code 1', 1));
104+
->with('config:show', 'some/key')
105+
->willReturn([]);
95106

96-
$this->assertNull($this->config->get('some/key'));
107+
$this->assertSame('', $this->config->get('some/key'));
97108
}
98109

99110
/**

src/Test/Unit/Patch/ApplierTest.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,13 +219,14 @@ public function testApplyPatchAlreadyApplied()
219219

220220
/**
221221
* @param string $command
222-
* @throws RuntimeException when the command isn't a reverse
222+
* @return array
223+
* @throws \RuntimeException when the command isn't a reverse
223224
*/
224225
public function shellMockReverseCallback(string $command)
225226
{
226227
if (strpos($command, '--reverse') !== false && strpos($command, '--check') !== false) {
227228
// Command was the reverse check, it's all good.
228-
return;
229+
return [];
229230
}
230231

231232
// Not a reverse, better throw an exception.

0 commit comments

Comments
 (0)