Skip to content

Commit 21bd91d

Browse files
authored
Merge pull request #2 from magento-commerce/imported-magento-magento-cloud-patches-78
[Imported] MC 37324: Add fallback to 'patch' command when 'git' command is not available
2 parents ca0ad72 + 0415656 commit 21bd91d

30 files changed

+756
-243
lines changed

config/services.xml

+11
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@
2727
<service id="Magento\CloudPatches\Patch\Pool\RequiredPool" lazy="true"/>
2828
<service id="Magento\CloudPatches\Patch\Pool\LocalPool" lazy="true"/>
2929
<service id="Magento\CloudPatches\Patch\Status\StatusPool" autowire="false"/>
30+
<service id="Magento\CloudPatches\Patch\PatchCommandNotFound" autowire="false"/>
31+
<service id="Magento\CloudPatches\Patch\PatchCommandException" autowire="false"/>
32+
<service id="Magento\CloudPatches\Shell\Command\DriverException" autowire="false"/>
33+
<service id="Magento\CloudPatches\Patch\PatchCommand" autowire="false"/>
34+
<service id="Magento\CloudPatches\Patch\PatchCommandInterface" alias="Magento\CloudPatches\Patch\PatchCommand"/>
3035
<service id="statusPool" class="Magento\CloudPatches\Patch\Status\StatusPool" lazy="true">
3136
<argument key="$resolvers" type="collection">
3237
<argument type="service" id="Magento\CloudPatches\Patch\Status\LocalResolver"/>
@@ -76,5 +81,11 @@
7681
<argument key="$actionPool" type="service" id="ApplyOptionalActionPool"/>
7782
</service>
7883
<service id="Magento\CloudPatches\Patch\PatchBuilder" shared="false"/>
84+
<service id="Magento\CloudPatches\Patch\PatchCommand">
85+
<argument key="$drivers" type="collection">
86+
<argument type="service" id="Magento\CloudPatches\Shell\Command\GitDriver"/>
87+
<argument type="service" id="Magento\CloudPatches\Shell\Command\PatchDriver"/>
88+
</argument>
89+
</service>
7990
</services>
8091
</container>

src/Command/Process/Action/RevertAction.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ private function printPatchRevertingFailed(OutputInterface $output, PatchInterfa
179179
'Reverting patch %s (%s) failed.%s',
180180
$patch->getId(),
181181
$patch->getPath(),
182-
$this->renderer->formatErrorOutput($errorOutput)
182+
PHP_EOL . $errorOutput
183183
);
184184

185185
$this->logger->error($errorMessage);

src/Command/Process/ApplyLocal.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,13 @@ public function run(InputInterface $input, OutputInterface $output)
8989
$this->printInfo($output, $message);
9090
array_push($appliedPatches, $patch);
9191
} catch (ApplierException $exception) {
92-
$this->printError($output, 'Error: patch conflict happened');
92+
$this->printError($output, 'Error: patch can\'t be applied');
9393
$messages = $this->rollbackProcessor->process($appliedPatches);
9494
$output->writeln($messages);
9595
$errorMessage = sprintf(
9696
'Applying patch %s failed.%s',
9797
$patch->getPath(),
98-
$this->renderer->formatErrorOutput($exception->getMessage())
98+
PHP_EOL . $exception->getMessage()
9999
);
100100

101101
throw new RuntimeException($errorMessage, $exception->getCode());

src/Command/Process/Ece/Revert.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ function ($patch) {
121121
$errorMessage = sprintf(
122122
'Reverting patch %s failed.%s',
123123
$patch->getPath(),
124-
$this->renderer->formatErrorOutput($exception->getMessage())
124+
PHP_EOL . $exception->getMessage()
125125
);
126126
$this->printError($output, $errorMessage);
127127
}

src/Command/Process/Renderer.php

-15
Original file line numberDiff line numberDiff line change
@@ -140,21 +140,6 @@ public function printPatchInfo(
140140
$output->writeln('');
141141
}
142142

143-
/**
144-
* Format error output.
145-
*
146-
* @param string $errorOutput
147-
* @return string
148-
*/
149-
public function formatErrorOutput(string $errorOutput): string
150-
{
151-
if (preg_match('#^.*?Error Output:(?<errors>.*?)$#is', $errorOutput, $matches)) {
152-
$errorOutput = PHP_EOL . 'Error Output:' . $matches['errors'];
153-
}
154-
155-
return $errorOutput;
156-
}
157-
158143
/**
159144
* Asks a confirmation question to the user.
160145
*

src/Command/Process/ShowStatus.php

+7-2
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,14 @@ function ($patch) {
111111
*/
112112
private function printDetailsInfo(OutputInterface $output)
113113
{
114+
$supportUrl = 'https://support.magento.com';
115+
$releaseNotesUrl = 'https://devdocs.magento.com/quality-patches/release-notes.html';
116+
114117
$output->writeln(
115-
'<info>More detailed information about patches you can find on </info>' .
116-
'<href=https://support.magento.com>https://support.magento.com</>'
118+
'<info>Patch details you can find on </info>' .
119+
sprintf('<href=%1$s>%1$s</> <info>(search for patch id, ex. MDVA-30265)</info>', $supportUrl) .
120+
PHP_EOL .
121+
sprintf('<info>Release notes</info> <href=%1$s>%1$s</>', $releaseNotesUrl)
117122
);
118123
}
119124

src/Patch/Applier.php

+19-28
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,16 @@
1010
use Magento\CloudPatches\Composer\MagentoVersion;
1111
use Magento\CloudPatches\Filesystem\Filesystem;
1212
use Magento\CloudPatches\Patch\Status\StatusPool;
13-
use Magento\CloudPatches\Shell\ProcessFactory;
14-
use Symfony\Component\Process\Exception\ProcessFailedException;
1513

1614
/**
1715
* Applies and reverts patches.
1816
*/
1917
class Applier
2018
{
2119
/**
22-
* @var ProcessFactory
20+
* @var PatchCommandInterface
2321
*/
24-
private $processFactory;
22+
private $patchCommand;
2523

2624
/**
2725
* @var GitConverter
@@ -39,18 +37,18 @@ class Applier
3937
private $filesystem;
4038

4139
/**
42-
* @param ProcessFactory $processFactory
40+
* @param PatchCommandInterface $patchCommand
4341
* @param GitConverter $gitConverter
4442
* @param MagentoVersion $magentoVersion
4543
* @param Filesystem $filesystem
4644
*/
4745
public function __construct(
48-
ProcessFactory $processFactory,
46+
PatchCommandInterface $patchCommand,
4947
GitConverter $gitConverter,
5048
MagentoVersion $magentoVersion,
5149
Filesystem $filesystem
5250
) {
53-
$this->processFactory = $processFactory;
51+
$this->patchCommand = $patchCommand;
5452
$this->gitConverter = $gitConverter;
5553
$this->magentoVersion = $magentoVersion;
5654
$this->filesystem = $filesystem;
@@ -69,13 +67,11 @@ public function apply(string $path, string $id): string
6967
{
7068
$content = $this->readContent($path);
7169
try {
72-
$this->processFactory->create(['git', 'apply'], $content)
73-
->mustRun();
74-
} catch (ProcessFailedException $exception) {
70+
$this->patchCommand->apply($content);
71+
} catch (PatchCommandException $exception) {
7572
try {
76-
$this->processFactory->create(['git', 'apply', '--check', '--reverse'], $content)
77-
->mustRun();
78-
} catch (ProcessFailedException $reverseException) {
73+
$this->patchCommand->revertCheck($content);
74+
} catch (PatchCommandException $reverseException) {
7975
throw new ApplierException($exception->getMessage(), $exception->getCode());
8076
}
8177

@@ -98,13 +94,11 @@ public function revert(string $path, string $id): string
9894
{
9995
$content = $this->readContent($path);
10096
try {
101-
$this->processFactory->create(['git', 'apply', '--reverse'], $content)
102-
->mustRun();
103-
} catch (ProcessFailedException $exception) {
97+
$this->patchCommand->revert($content);
98+
} catch (PatchCommandException $exception) {
10499
try {
105-
$this->processFactory->create(['git', 'apply', '--check'], $content)
106-
->mustRun();
107-
} catch (ProcessFailedException $applyException) {
100+
$this->patchCommand->applyCheck($content);
101+
} catch (PatchCommandException $applyException) {
108102
throw new ApplierException($exception->getMessage(), $exception->getCode());
109103
}
110104

@@ -124,13 +118,11 @@ public function status(string $patchContent): string
124118
{
125119
$patchContent = $this->prepareContent($patchContent);
126120
try {
127-
$this->processFactory->create(['git', 'apply', '--check'], $patchContent)
128-
->mustRun();
129-
} catch (ProcessFailedException $exception) {
121+
$this->patchCommand->applyCheck($patchContent);
122+
} catch (PatchCommandException $exception) {
130123
try {
131-
$this->processFactory->create(['git', 'apply', '--check', '--reverse'], $patchContent)
132-
->mustRun();
133-
} catch (ProcessFailedException $reverseException) {
124+
$this->patchCommand->revertCheck($patchContent);
125+
} catch (PatchCommandException $reverseException) {
134126
return StatusPool::NA;
135127
}
136128

@@ -150,9 +142,8 @@ public function checkApply(string $patchContent): bool
150142
{
151143
$patchContent = $this->prepareContent($patchContent);
152144
try {
153-
$this->processFactory->create(['git', 'apply', '--check'], $patchContent)
154-
->mustRun();
155-
} catch (ProcessFailedException $exception) {
145+
$this->patchCommand->applyCheck($patchContent);
146+
} catch (PatchCommandException $exception) {
156147
return false;
157148
}
158149

src/Patch/Conflict/Processor.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public function process(
7373
array $appliedPatches,
7474
string $exceptionMessage
7575
) {
76-
$errorMessage = 'Error: patch conflict happened';
76+
$errorMessage = 'Error: patch can\'t be applied';
7777
$this->logger->error($errorMessage);
7878
$output->writeln('<error>' . $errorMessage . '</error>');
7979

@@ -84,7 +84,7 @@ public function process(
8484
'Applying patch %s (%s) failed.%s%s',
8585
$patch->getId(),
8686
$patch->getPath(),
87-
$this->renderer->formatErrorOutput($exceptionMessage),
87+
PHP_EOL . $exceptionMessage,
8888
$conflictDetails ? PHP_EOL . $conflictDetails : ''
8989
);
9090

src/Patch/PatchCommand.php

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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\CloudPatches\Patch;
9+
10+
use Magento\CloudPatches\Shell\Command\DriverInterface;
11+
12+
/**
13+
* Patch command selector
14+
*/
15+
class PatchCommand implements PatchCommandInterface
16+
{
17+
/**
18+
* @var DriverInterface[]
19+
*/
20+
private $drivers;
21+
22+
/**
23+
* @var DriverInterface
24+
*/
25+
private $driver;
26+
27+
/**
28+
* @param DriverInterface[] $drivers
29+
*/
30+
public function __construct(
31+
array $drivers
32+
) {
33+
$this->drivers = $drivers;
34+
}
35+
36+
/**
37+
* @inheritDoc
38+
*/
39+
public function apply(string $patch)
40+
{
41+
$this->getDriver()->apply($patch);
42+
}
43+
44+
/**
45+
* @inheritDoc
46+
*/
47+
public function revert(string $patch)
48+
{
49+
$this->getDriver()->revert($patch);
50+
}
51+
52+
/**
53+
* @inheritDoc
54+
*/
55+
public function applyCheck(string $patch)
56+
{
57+
$this->getDriver()->applyCheck($patch);
58+
}
59+
60+
/**
61+
* @inheritDoc
62+
*/
63+
public function revertCheck(string $patch)
64+
{
65+
$this->getDriver()->revertCheck($patch);
66+
}
67+
68+
/**
69+
* Returns first available driver
70+
*
71+
* @return DriverInterface
72+
* @throws PatchCommandNotFound
73+
*/
74+
private function getDriver(): DriverInterface
75+
{
76+
if ($this->driver === null) {
77+
foreach ($this->drivers as $driver) {
78+
if ($driver->isInstalled()) {
79+
$this->driver = $driver;
80+
break;
81+
}
82+
}
83+
if ($this->driver === null) {
84+
throw new PatchCommandNotFound();
85+
}
86+
}
87+
return $this->driver;
88+
}
89+
}

src/Patch/PatchCommandException.php

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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\CloudPatches\Patch;
9+
10+
use Magento\CloudPatches\App\GenericException;
11+
12+
/**
13+
* Generic patch command exception
14+
*/
15+
class PatchCommandException extends GenericException
16+
{
17+
}

src/Patch/PatchCommandInterface.php

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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\CloudPatches\Patch;
9+
10+
/**
11+
* Patch command interface
12+
*/
13+
interface PatchCommandInterface
14+
{
15+
/**
16+
* Applies patch
17+
*
18+
* @param string $patch
19+
* @return void
20+
* @throws PatchCommandException
21+
*/
22+
public function apply(string $patch);
23+
24+
/**
25+
* Reverts patch
26+
*
27+
* @param string $patch
28+
* @return void
29+
* @throws PatchCommandException
30+
*/
31+
public function revert(string $patch);
32+
33+
/**
34+
* Checks if patch can be applied.
35+
*
36+
* @param string $patch
37+
* @return void
38+
* @throws PatchCommandException
39+
*/
40+
public function applyCheck(string $patch);
41+
42+
/**
43+
* Checks if patch can be reverted
44+
*
45+
* @param string $patch
46+
* @return void
47+
* @throws PatchCommandException
48+
*/
49+
public function revertCheck(string $patch);
50+
}

0 commit comments

Comments
 (0)