From a8b38a29f9e9593ddd0457a081427c9482da5559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20M=C3=BCnch?= Date: Mon, 21 Apr 2025 17:17:54 +0200 Subject: [PATCH 1/3] feat: apply github patch directly fixes: #1622 related to: #1594 --- .../Github/PatchFileContent/Creator.php | 10 ++-- .../Processor/AppCodeProcessor.php | 6 +-- .../Processor/AppDesignProcessor.php | 6 +-- .../Processor/I18nProcessor.php | 6 +-- .../Processor/LibProcessor.php | 8 +-- .../Processor/ProcessorInterface.php | 2 +- .../Command/Github/PullRequestCommand.php | 49 ++++++++++++++++--- 7 files changed, 62 insertions(+), 25 deletions(-) diff --git a/src/N98/Magento/Command/Github/PatchFileContent/Creator.php b/src/N98/Magento/Command/Github/PatchFileContent/Creator.php index 22cafa2a1..c1b74e2fd 100644 --- a/src/N98/Magento/Command/Github/PatchFileContent/Creator.php +++ b/src/N98/Magento/Command/Github/PatchFileContent/Creator.php @@ -15,19 +15,19 @@ class Creator * @param string $diffContent * @return string */ - public static function create(string $diffContent): string + public static function create(string $diffContent, string $replaceVendor): string { $appDesignProcessor = new AppDesignProcessor(); - $diffContent = $appDesignProcessor->process($diffContent); + $diffContent = $appDesignProcessor->process($diffContent, $replaceVendor); $appCodeProcessor = new AppCodeProcessor(); - $diffContent = $appCodeProcessor->process($diffContent); + $diffContent = $appCodeProcessor->process($diffContent, $replaceVendor); $i18nProcessor = new I18nProcessor(); - $diffContent = $i18nProcessor->process($diffContent); + $diffContent = $i18nProcessor->process($diffContent, $replaceVendor); $libProcessor = new LibProcessor(); - $diffContent = $libProcessor->process($diffContent); + $diffContent = $libProcessor->process($diffContent, $replaceVendor); return $diffContent; } diff --git a/src/N98/Magento/Command/Github/PatchFileContent/Processor/AppCodeProcessor.php b/src/N98/Magento/Command/Github/PatchFileContent/Processor/AppCodeProcessor.php index 0ac9b8d91..68bb23b7b 100644 --- a/src/N98/Magento/Command/Github/PatchFileContent/Processor/AppCodeProcessor.php +++ b/src/N98/Magento/Command/Github/PatchFileContent/Processor/AppCodeProcessor.php @@ -6,13 +6,13 @@ class AppCodeProcessor implements ProcessorInterface { - public function process(string $diffContent): string + public function process(string $diffContent, string $replaceVendor): string { - $callback = function ($matches) { + $callback = function ($matches) use ($replaceVendor) { // camelcase to dash $matches[1] = preg_replace('/([a-z])([A-Z])/', '$1-$2', $matches[1]); - return 'vendor/magento/module-' . strtolower($matches[1]) . '/'; + return 'vendor/' . $replaceVendor . '/module-' . strtolower($matches[1]) . '/'; }; return (string) preg_replace_callback('/app\/code\/Magento\/([a-zA-Z0-9_]+)\//', $callback, $diffContent); diff --git a/src/N98/Magento/Command/Github/PatchFileContent/Processor/AppDesignProcessor.php b/src/N98/Magento/Command/Github/PatchFileContent/Processor/AppDesignProcessor.php index d8fafec94..be7b7ea2a 100644 --- a/src/N98/Magento/Command/Github/PatchFileContent/Processor/AppDesignProcessor.php +++ b/src/N98/Magento/Command/Github/PatchFileContent/Processor/AppDesignProcessor.php @@ -6,19 +6,19 @@ class AppDesignProcessor implements ProcessorInterface { - public function process(string $diffContent): string + public function process(string $diffContent, string $replaceVendor): string { // preg_replace app/design/frontend/Magento// with vendor/magento/theme-frontend-/ $diffContent = preg_replace( '/app\/design\/frontend\/Magento\/([a-zA-Z0-9_]+)\//', - 'vendor/magento/theme-frontend-$1/', + 'vendor/' . $replaceVendor . '/theme-frontend-$1/', $diffContent ); // preg_replace app/design/adminhtml/Magento// with vendor/magento/theme-adminhtml-/ $diffContent = preg_replace( '/app\/design\/adminhtml\/Magento\/([a-zA-Z0-9_]+)\//', - 'vendor/magento/theme-adminhtml-$1/', + 'vendor/' . $replaceVendor . '/theme-adminhtml-$1/', $diffContent ); diff --git a/src/N98/Magento/Command/Github/PatchFileContent/Processor/I18nProcessor.php b/src/N98/Magento/Command/Github/PatchFileContent/Processor/I18nProcessor.php index 80dc4aeb8..043c4f1db 100644 --- a/src/N98/Magento/Command/Github/PatchFileContent/Processor/I18nProcessor.php +++ b/src/N98/Magento/Command/Github/PatchFileContent/Processor/I18nProcessor.php @@ -6,12 +6,12 @@ class I18nProcessor implements ProcessorInterface { - public function process(string $diffContent): string + public function process(string $diffContent, string $replaceVendor): string { $diffContent = preg_replace_callback( '/app\/i18n\/([a-zA-Z0-9_]+)\//', - function ($matches) { - return 'vendor/magento/language-' . strtolower($matches[1]) . '/'; + function ($matches) use ($replaceVendor) { + return 'vendor/' . $replaceVendor . '/language-' . strtolower($matches[1]) . '/'; }, $diffContent ); diff --git a/src/N98/Magento/Command/Github/PatchFileContent/Processor/LibProcessor.php b/src/N98/Magento/Command/Github/PatchFileContent/Processor/LibProcessor.php index 1d027c29c..5aa87e0a0 100644 --- a/src/N98/Magento/Command/Github/PatchFileContent/Processor/LibProcessor.php +++ b/src/N98/Magento/Command/Github/PatchFileContent/Processor/LibProcessor.php @@ -6,21 +6,21 @@ class LibProcessor implements ProcessorInterface { - public function process(string $diffContent): string + public function process(string $diffContent, string $replaceVendor): string { // edge cases -> Message Queue is part of the framework directory but later on in an own package $diffContent = preg_replace( '/lib\/internal\/Magento\/Framework\/MessageQueue\/([a-zA-Z0-9_]+)\//', - 'vendor/magento/framework-message-queue/$1/', + 'vendor/' . $replaceVendor . '/framework-message-queue/$1/', $diffContent ); // Handle the rest of the lib/internal/Magento directory - $callback = function ($matches) { + $callback = function ($matches) use ($replaceVendor) { // camelcase to dash $matches[1] = preg_replace('/([a-z])([A-Z])/', '$1-$2', $matches[1]); - return 'vendor/magento/' . strtolower($matches[1]) . '/'; + return 'vendor/' . $replaceVendor . '/' . strtolower($matches[1]) . '/'; }; $diffContent = (string) preg_replace_callback( diff --git a/src/N98/Magento/Command/Github/PatchFileContent/Processor/ProcessorInterface.php b/src/N98/Magento/Command/Github/PatchFileContent/Processor/ProcessorInterface.php index 8276edb9f..e62abe873 100644 --- a/src/N98/Magento/Command/Github/PatchFileContent/Processor/ProcessorInterface.php +++ b/src/N98/Magento/Command/Github/PatchFileContent/Processor/ProcessorInterface.php @@ -6,5 +6,5 @@ interface ProcessorInterface { - public function process(string $diffContent): string; + public function process(string $diffContent, string $replaceVendor): string; } diff --git a/src/N98/Magento/Command/Github/PullRequestCommand.php b/src/N98/Magento/Command/Github/PullRequestCommand.php index 673b0d5c0..317535f7a 100644 --- a/src/N98/Magento/Command/Github/PullRequestCommand.php +++ b/src/N98/Magento/Command/Github/PullRequestCommand.php @@ -5,12 +5,15 @@ use N98\Magento\Command\AbstractMagentoCommand; use N98\Magento\Command\Github\PatchFileContent\Creator as PatchFileContentCreator; use N98\Util\OperatingSystem; +use RuntimeException; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Process\Process; use WpOrg\Requests\Requests; +use WpOrg\Requests\Response; class PullRequestCommand extends AbstractMagentoCommand { @@ -29,6 +32,7 @@ protected function configure() ->addOption('repository', 'r', InputOption::VALUE_OPTIONAL, 'Repository to fetch from', 'magento/magento2') ->addOption('mage-os', null, InputOption::VALUE_NONE, 'Shortcut option to use the mage-os/mageos-magento2 repository.') ->addOption('patch', 'd', InputOption::VALUE_NONE, 'Download patch and prepare it for applying') + ->addOption('apply', 'a', InputOption::VALUE_NONE, 'Apply patch to current working directory') ->addOption('diff', null, InputOption::VALUE_NONE, 'Raw diff download') ->addOption('json', null, InputOption::VALUE_NONE, 'Show pull request data as json') ->setDescription('Download patch from github merge request (experimental)'); @@ -73,11 +77,21 @@ protected function execute(InputInterface $input, OutputInterface $output) $table->render(); if ($input->getOption('patch')) { - $this->patchFile($prData, $output); + $replaceVendor = 'magento'; + if ($input->getOption('mage-os')) { + $replaceVendor = 'mage-os'; + } + + $patchFilename = $this->patchFile($prData, $replaceVendor, $output); + + if ($input->getOption('apply')) { + $this->applyPatch($output, $patchFilename); + } } if (!$input->getOption('patch') && !$input->getOption('diff')) { $output->writeln('Use --patch to download the patch as ready to apply patch file'); + $output->writeln('Use --patch --apply to download the patch and directly apply it'); $output->writeln('Use --diff to see the raw diff'); } @@ -100,13 +114,15 @@ protected function fetchDiffContent($diffUrl): string /** * @param array $prData + * @param string $replaceVendor * @param OutputInterface $output - * @return void + * @return string Patch file name */ - protected function patchFile(array $prData, OutputInterface $output): void + protected function patchFile(array $prData, string $replaceVendor, OutputInterface $output): string { $patchFileContent = PatchFileContentCreator::create( - $this->fetchDiffContent($prData['diff_url']) + $this->fetchDiffContent($prData['diff_url']), + $replaceVendor ); $filename = sprintf( @@ -117,17 +133,19 @@ protected function patchFile(array $prData, OutputInterface $output): void chdir(OperatingSystem::getCwd()); if (file_put_contents($filename, $patchFileContent) === false) { - throw new \RuntimeException('Could not write patch file'); + throw new RuntimeException('Could not write patch file'); } $output->writeln(sprintf('Patch file created: %s', $filename)); + + return $filename; } /** * @param InputInterface $input * @return \WpOrg\Requests\Response */ - protected function getPullRequestInfoByApi(InputInterface $input): \WpOrg\Requests\Response + protected function getPullRequestInfoByApi(InputInterface $input): Response { $pullRequestDataResponse = Requests::get( sprintf( @@ -140,4 +158,23 @@ protected function getPullRequestInfoByApi(InputInterface $input): \WpOrg\Reques ); return $pullRequestDataResponse; } + + /** + * @param \Symfony\Component\Console\Output\OutputInterface $output + * @param string $patchFilename + * @return void + */ + protected function applyPatch(OutputInterface $output, string $patchFilename): void + { + $output->writeln('Applying patch...'); + + $process = new Process(['patch', '-p1']); + $process->setInput(file_get_contents($patchFilename)); + $process->setTimeout(3600); + $process->setWorkingDirectory(OperatingSystem::getCwd()); + $process->start(); + $process->wait(function ($type, $buffer) use ($output) { + $output->write('patch > ' . $buffer . '', false); + }); + } } From b5dc8296e566956264df8235e61402691eb480be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20M=C3=BCnch?= Date: Mon, 21 Apr 2025 17:20:10 +0200 Subject: [PATCH 2/3] chore: document new apply option --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 35ef4d5c6..1da3a61a4 100644 --- a/README.md +++ b/README.md @@ -1278,6 +1278,16 @@ n98-magerun2.phar github:pr:patch --mage-os n98-magerun2.phar github:pr:patch --patch ``` +*Directly apply the patch:* + +```sh +# Magento 2 Open Source +n98-magerun2.phar github:pr:patch --patch --apply + +# for Mage-OS +n98-magerun2.phar github:pr:patch --mage-os --patch --apply +``` + Files of the magento2-base and magento2-ee-base and b2b base packages are currently not handled by the command. **List only the raw diff:** From 36d1b2e2f07498bc1f55ea10a818d080967ad6b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20M=C3=BCnch?= Date: Mon, 21 Apr 2025 17:28:22 +0200 Subject: [PATCH 3/3] fix: broken unit tests after changing processor interface --- .../Github/PatchFileContent/CreatorTest.php | 14 ++++++++++++-- .../Processor/AppCodeProcessorTest.php | 2 +- .../Processor/AppDesignProcessorTest.php | 2 +- .../Processor/I18nProcessorTest.php | 2 +- .../Processor/LibProcessorTest.php | 2 +- 5 files changed, 16 insertions(+), 6 deletions(-) diff --git a/tests/N98/Magento/Command/Github/PatchFileContent/CreatorTest.php b/tests/N98/Magento/Command/Github/PatchFileContent/CreatorTest.php index 5081d4317..d3af7c868 100644 --- a/tests/N98/Magento/Command/Github/PatchFileContent/CreatorTest.php +++ b/tests/N98/Magento/Command/Github/PatchFileContent/CreatorTest.php @@ -8,12 +8,22 @@ class CreatorTest extends TestCase { - public function testCreate() + public function testCreateWithVendorMagento() { $diffContent = 'app/code/Magento/SampleModule/'; $expectedResult = 'vendor/magento/module-sample-module/'; - $result = Creator::create($diffContent); + $result = Creator::create($diffContent, 'magento'); + + $this->assertEquals($expectedResult, $result); + } + + public function testCreateWithVendorMageOS() + { + $diffContent = 'app/code/Magento/SampleModule/'; + $expectedResult = 'vendor/mage-os/module-sample-module/'; + + $result = Creator::create($diffContent, 'mage-os'); $this->assertEquals($expectedResult, $result); } diff --git a/tests/N98/Magento/Command/Github/PatchFileContent/Processor/AppCodeProcessorTest.php b/tests/N98/Magento/Command/Github/PatchFileContent/Processor/AppCodeProcessorTest.php index fc907eb54..568f310b2 100644 --- a/tests/N98/Magento/Command/Github/PatchFileContent/Processor/AppCodeProcessorTest.php +++ b/tests/N98/Magento/Command/Github/PatchFileContent/Processor/AppCodeProcessorTest.php @@ -15,6 +15,6 @@ public function testProcess() $processor = new AppCodeProcessor(); - $this->assertEquals($expectedResult, $processor->process($diffContent)); + $this->assertEquals($expectedResult, $processor->process($diffContent, 'magento')); } } diff --git a/tests/N98/Magento/Command/Github/PatchFileContent/Processor/AppDesignProcessorTest.php b/tests/N98/Magento/Command/Github/PatchFileContent/Processor/AppDesignProcessorTest.php index 24179f51e..ed7a69c3a 100644 --- a/tests/N98/Magento/Command/Github/PatchFileContent/Processor/AppDesignProcessorTest.php +++ b/tests/N98/Magento/Command/Github/PatchFileContent/Processor/AppDesignProcessorTest.php @@ -17,7 +17,7 @@ public function testProcess() $this->assertSame( $expectedResult, - $processor->process($diffContent) + $processor->process($diffContent, 'magento'), ); } } diff --git a/tests/N98/Magento/Command/Github/PatchFileContent/Processor/I18nProcessorTest.php b/tests/N98/Magento/Command/Github/PatchFileContent/Processor/I18nProcessorTest.php index e1fab47b3..2dd806973 100644 --- a/tests/N98/Magento/Command/Github/PatchFileContent/Processor/I18nProcessorTest.php +++ b/tests/N98/Magento/Command/Github/PatchFileContent/Processor/I18nProcessorTest.php @@ -22,6 +22,6 @@ public function testProcess() $processor = new I18nProcessor(); - $this->assertEquals($expectedResult, $processor->process($diffContent)); + $this->assertEquals($expectedResult, $processor->process($diffContent, 'magento')); } } diff --git a/tests/N98/Magento/Command/Github/PatchFileContent/Processor/LibProcessorTest.php b/tests/N98/Magento/Command/Github/PatchFileContent/Processor/LibProcessorTest.php index 0ea0b9b58..2daecff84 100644 --- a/tests/N98/Magento/Command/Github/PatchFileContent/Processor/LibProcessorTest.php +++ b/tests/N98/Magento/Command/Github/PatchFileContent/Processor/LibProcessorTest.php @@ -22,6 +22,6 @@ public function testProcess() $processor = new I18nProcessor(); - $this->assertEquals($expectedResult, $processor->process($diffContent)); + $this->assertEquals($expectedResult, $processor->process($diffContent, 'magento')); } }