diff --git a/src/ComposerJsonFromLockBuilder.php b/src/ComposerJsonFromLockBuilder.php new file mode 100644 index 0000000..0da79d8 --- /dev/null +++ b/src/ComposerJsonFromLockBuilder.php @@ -0,0 +1,53 @@ +composerLockPath) + ?: throw new \Exception('Couldn\'t open composer lock file from ' . $this->composerLockPath); + $composerJsonContents = file_get_contents($this->composerJsonPath) + ?: throw new \Exception('Couldn\'t open composer json file from ' . $this->composerJsonPath); + + $types = ['require', 'require-dev']; + + foreach ($types as $type) { + foreach ($this->dependencies($composerJsonContents, $type) as $dependency => $version) { + preg_match('#"name": ' . preg_quote($dependency) . ',\s+"version": "(.+)"#m', $composerLockContents, $match); + + if (isset($match[1])) { + $lockVersion = str_contains($match[1],'dev')? $match[1] : '^'.$match[1]; + $composerJsonContents = str_replace( + $dependency . ': ' . $version, + $dependency . ': "' . $lockVersion . '"', + $composerJsonContents + ); + } + } + } + + return $composerJsonContents; + } + + private + function dependencies(string $composerJsonContents, string $dependencyType): array + { + preg_match('/"' . preg_quote($dependencyType) . '":\s+{([\s\S]+?)}/', $composerJsonContents, $dependencies); + $dependencies = preg_split('/,/ms', $dependencies[1]); + $composerDependencies = []; + foreach ($dependencies as &$dependency) { + $dependency = preg_replace('/\s+/ms', '', $dependency); + $dependency = explode(':', $dependency); + $composerDependencies[$dependency[0]] = $dependency[1]; + } + + return $composerDependencies; + } +} \ No newline at end of file diff --git a/src/MajorConstraintUpdater.php b/src/MajorConstraintUpdater.php index 08de46c..9ec560d 100644 --- a/src/MajorConstraintUpdater.php +++ b/src/MajorConstraintUpdater.php @@ -3,6 +3,7 @@ namespace MartinsR\ComposerConstraintUpdater; use Composer\Command\BaseCommand; +use Composer\Factory; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; @@ -12,7 +13,6 @@ class MajorConstraintUpdater extends BaseCommand protected function configure() { - // @codingStandardsIgnoreStart $this ->setName('major-update') ->setDescription( @@ -22,11 +22,17 @@ protected function configure() ) ->setDefinition([ new InputOption( - 'composer-path', - 'C', - InputOption::VALUE_REQUIRED, + 'composer-json', + null, + InputOption::VALUE_OPTIONAL, 'Composer json file location' ), + new InputOption( + 'composer-lock', + null, + InputOption::VALUE_OPTIONAL, + 'Composer lock file location' + ), new InputOption( 'constraint', null, @@ -40,26 +46,34 @@ protected function configure() you can use major-update -C=composer-path --constraint=package/package:^9.0.0. This command will automatically resolve the conflicts in composer.json, saving you the trouble of doing it manually EOT ); - // @codingStandardsIgnoreEnd } protected function execute(InputInterface $input, OutputInterface $output): int { - $composerPath = $input->getOption('composer-path'); -// $composerFileContents = file_get_contents($composerPath); -// $constraints = []; -// -// foreach ($input->getOption('constraint') as $option) { -// $input = explode(':', $option); -// $constraints[$input[0]] = $input[1]; -// } -// file_put_contents($composerPath, $this->replaceVersions($composerFileContents, $constraints)); -// -// $this->updateComposer(); - - file_put_contents($composerPath, $this->versionsFromLock($composerPath)); + $composerPath = $input->getOption('composer-json') ?? Factory::getComposerFile(); + $composerLock = $input->getOption('composer-lock') ?? Factory::getLockFile($composerPath); + + $composerFileContents = file_get_contents($composerPath) ?: throw new \Exception('Couldn\'t open the composer json from ' . $composerPath); + + $constraints = []; + foreach ($input->getOption('constraint') as $option) { + $input = explode(':', $option); + $constraints[$input[0]] = $input[1]; + } + + $output->writeln('Building composer.json for update'); + file_put_contents($composerPath, $this->replaceVersions($composerFileContents, $constraints)); + + $output->writeln('Launching composer update'); + $this->updateComposer(); + + $output->writeln('Rebuilding composer.json from lock'); + file_put_contents($composerPath, (new ComposerJsonFromLockBuilder($composerPath, $composerLock))->versionsFromLock()); + + $output->writeln('Composer.json has been successfully updated!'); + return 1; } @@ -70,30 +84,6 @@ private function updateComposer(): void echo $update; } - public function versionsFromLock(string $composerPath) - { - $composerLockPath = str_replace('composer.json', 'composer.lock', $composerPath); - - $composerLockContents = file_get_contents($composerLockPath); - $composerJsonContents = file_get_contents($composerPath); - - $types = ['require' => 'packages', 'require-dev' => 'packages-dev']; - foreach ($types as $typeJson => $typeLock) { - preg_match('/"' . preg_quote($typeJson) . '":\s+{([\s\S]+?)}/', $composerJsonContents, $dependencies); - $dependencies = $this->processDependencies(preg_split('/,/ms', $dependencies[1])); - foreach ($dependencies as $dependencyName => $version) { - preg_match('#"name": ' . preg_quote($dependencyName) . ',\s+"version": "(.+)"#m', $composerLockContents, $match); - if (isset($match[1])) { - echo $dependencyName . ': ' . $version; - $composerJsonContents = str_replace($dependencyName . ': ' . $version, $dependencyName . ': "^' . $match[1] . '"', $composerJsonContents); - } - } - } - - return $composerJsonContents; - - } - public function replaceVersions(string $composerContents, array $packageConstraints): string { @@ -113,17 +103,4 @@ function replaceVersions(string $composerContents, array $packageConstraints): s return $composerContents; } - - private - function processDependencies(array $dependencies): array - { - $composerDependencies = []; - foreach ($dependencies as &$dependency) { - $dependency = preg_replace('/\s+/ms', '', $dependency); - $dependency = explode(':', $dependency); - $composerDependencies[$dependency[0]] = $dependency[1]; - } - - return $composerDependencies; - } -} +} \ No newline at end of file diff --git a/src/MinorConstraintUpdater.php b/src/MinorConstraintUpdater.php index 62566b3..e456ec4 100644 --- a/src/MinorConstraintUpdater.php +++ b/src/MinorConstraintUpdater.php @@ -3,6 +3,7 @@ namespace MartinsR\ComposerConstraintUpdater; use Composer\Command\BaseCommand; +use Composer\Factory; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; @@ -12,12 +13,22 @@ class MinorConstraintUpdater extends BaseCommand protected function configure() { - // @codingStandardsIgnoreStart $this ->setName('minor-update') ->setDescription('Will run composer update and replace versions in your composer.json file to the ones inside lock file') ->setDefinition([ - new InputOption('composer-path', 'C', InputOption::VALUE_REQUIRED, 'Composer json file location'), + new InputOption( + 'composer-json', + null, + InputOption::VALUE_OPTIONAL, + 'Composer json file location' + ), + new InputOption( + 'composer-lock', + null, + InputOption::VALUE_OPTIONAL, + 'Composer lock file location' + ), ]) ->setHelp(<<minor-update command executes a composer update, which updates your composer.json @@ -25,17 +36,21 @@ protected function configure() This means it will update the versions of your packages to the latest minor versions, while respecting the version constraints defined in your composer.json file. EOT ); - // @codingStandardsIgnoreEnd } protected function execute(InputInterface $input, OutputInterface $output): int { - $composerPath = $input->getOption('composer-path'); + $composerPath = $input->getOption('composer-json') ?? Factory::getComposerFile(); + $composerLock = $input->getOption('composer-lock') ?? Factory::getLockFile($composerPath); + $output->writeln('Launching composer update'); $this->updateComposer(); - file_put_contents($composerPath, $this->versionsFromLock($composerPath)); + $output->writeln('Rebuilding composer.json from lock file'); + file_put_contents($composerPath, (new ComposerJsonFromLockBuilder($composerPath, $composerLock))->versionsFromLock()); + + $output->writeln('Composer.json has been successfully updated!'); return 1; } @@ -45,60 +60,4 @@ private function updateComposer(): void echo $update; } - - public function versionsFromLock(string $composerPath) - { - $composerLockPath = str_replace('composer.json', 'composer.lock', $composerPath); - - $composerLockContents = file_get_contents($composerLockPath); - $composerJsonContents = file_get_contents($composerPath); - - $types = ['require' => 'packages', 'require-dev' => 'packages-dev']; - foreach ($types as $typeJson => $typeLock) { - preg_match('/"' . preg_quote($typeJson) . '":\s+{([\s\S]+?)}/', $composerJsonContents, $dependencies); - $dependencies = $this->processDependencies(preg_split('/,/ms', $dependencies[1])); - foreach ($dependencies as $dependencyName => $version) { - preg_match('#"name": ' . preg_quote($dependencyName) . ',\s+"version": "(.+)"#m', $composerLockContents, $match); - if (isset($match[1])) { - echo $dependencyName . ': ' . $version; - $composerJsonContents = str_replace($dependencyName . ': ' . $version, $dependencyName . ': "^' . $match[1] . '"', $composerJsonContents); - } - } - } - - return $composerJsonContents; - } - - public - function replaceVersions(string $composerContents, array $packageConstraints): string - { - $requirements = ['require', 'require-dev']; - foreach ($requirements as $requirement) { - preg_match('/"' . preg_quote($requirement) . '"\s*:\s*\{([\s|\S]+?)\}/m', $composerContents, $matches); - $packages = preg_replace('/:\s*"(.*)+?"/m', ': "*"', $matches[1]); - foreach ($packageConstraints as $constraint => $version) { - $packages = preg_replace( - '@"' . preg_quote($constraint) . '"\s*:\s*"\*"@m', - '"' . preg_quote($constraint) . '": "' . $version . '"', - $packages - ); - } - $composerContents = preg_replace('/"' . preg_quote($requirement) . '"\s*:\s*\{([\s|\S]+?)\}/m', '"' . $requirement . '": {' . $packages . '}', $composerContents); - } - - return $composerContents; - } - - private - function processDependencies(array $dependencies): array - { - $composerDependencies = []; - foreach ($dependencies as &$dependency) { - $dependency = preg_replace('/\s+/ms', '', $dependency); - $dependency = explode(':', $dependency); - $composerDependencies[$dependency[0]] = $dependency[1]; - } - - return $composerDependencies; - } } \ No newline at end of file diff --git a/tests/unit/ComposerUpdaterTest.php b/tests/unit/ComposerUpdaterTest.php index edf93cd..ba33102 100644 --- a/tests/unit/ComposerUpdaterTest.php +++ b/tests/unit/ComposerUpdaterTest.php @@ -1,15 +1,15 @@ replaceVersions(file_get_contents('C:\Users\martins.rucevskis\projects\ComposerConstraintUpdater\tests\resources\composerjson.txt'), ['laravel/framework' => '9.0.0']); + (new MajorConstraintUpdater())->replaceVersions(file_get_contents('C:\Users\martins.rucevskis\projects\ComposerConstraintUpdater\tests\resources\composerjson.txt'), ['laravel/framework' => '9.0.0']); } public function testComposerJsonFromLockFile(): void{ - (new ConstraintUpdaterInitCommand())->versionsFromLock('C:\Users\martins.rucevskis\projects\ComposerConstraintUpdater\tests\resources\composer.json.txt'); + (new MajorConstraintUpdater())->versionsFromLock('C:\Users\martins.rucevskis\projects\ComposerConstraintUpdater\tests\resources\composer.json.txt'); } } \ No newline at end of file