diff --git a/docs/bard/index.md b/docs/bard/index.md
index 77007625..47810189 100644
--- a/docs/bard/index.md
+++ b/docs/bard/index.md
@@ -8,25 +8,25 @@ Bard is used to manage monorepos.
## Usage
-Initialize a new bard.json file
+Initialize a new bard.json file for new monorepos.
```shell
bard init
```
-Add repositories
+### Adding Repositories
```shell
bard add path/to/code repoUrl
```
-Push changes to read-only repos
+### Push changes to read-only repos
```shell
bard push
```
-Create a release
+### Create a release
```shell
bard release major
@@ -37,7 +37,19 @@ bard release patch
Bard will track the versions so you can just use the keywords: major, minor,
patch.
+### Copy files
+
Copy the LICENSE file from the root to all packages
```shell
bard copy LICENSE
```
+
+### Merging `composer.json` files
+
+When you have to maintain the composer.json files, this command will take the
+packages and merge those into the main composer.json file. It will also update
+the package's composer.json file with the correct values as well.
+
+```shell
+bard merge
+```
diff --git a/src/SonsOfPHP/Bard/composer.json b/src/SonsOfPHP/Bard/composer.json
index f1d905b6..151bdd29 100644
--- a/src/SonsOfPHP/Bard/composer.json
+++ b/src/SonsOfPHP/Bard/composer.json
@@ -15,6 +15,7 @@
"php": ">=8.1",
"sonsofphp/event-dispatcher": "^0.3.x-dev",
"sonsofphp/json": "^0.3.x-dev",
+ "sonsofphp/logger": "^0.3.x-dev",
"sonsofphp/version": "^0.3.x-dev",
"symfony/console": "^4 || ^5 || ^6",
"symfony/dotenv": "^5 || ^6",
@@ -66,4 +67,4 @@
"url": "https://tidelift.com/subscription/pkg/packagist-sonsofphp-sonsofphp"
}
]
-}
\ No newline at end of file
+}
diff --git a/src/SonsOfPHP/Bard/src/Console/Command/AddCommand.php b/src/SonsOfPHP/Bard/src/Console/Command/AddCommand.php
index 546e4551..97818dfc 100644
--- a/src/SonsOfPHP/Bard/src/Console/Command/AddCommand.php
+++ b/src/SonsOfPHP/Bard/src/Console/Command/AddCommand.php
@@ -24,26 +24,49 @@ protected function configure(): void
$this
->setDescription('Add new repo')
->addOption('branch', null, InputOption::VALUE_REQUIRED, 'What branch we working with?', 'main')
+ ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Dry Run (Do not make any changes)')
->addArgument('path', InputArgument::REQUIRED, 'Path where code will be')
- ->addArgument('repository', InputArgument::REQUIRED, 'Repository')
+ ->addArgument('repository', InputArgument::REQUIRED, 'Repository Uri')
+ ->setHelp(
+ <<<'HELP'
+The add command will add additional repositories that need to be managed
+into the `bard.json` file.
+
+Examples:
+
+ %command.full_name% src/SonsOfPHP/Bard git@github.com:vendor/package.git
+
+Read more at https://docs.sonsofphp.com/bard/
+HELP
+ )
;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$bardConfig = new JsonFile($input->getOption('working-dir') . '/bard.json');
- $formatter = $this->getHelper('formatter');
$io = new SymfonyStyle($input, $output);
+ $isDryRun = $input->getOption('dry-run');
+ // ---
if (null === $packages = $bardConfig->getSection('packages')) {
$packages = [];
}
-
- // @todo Check to make sure this package does not already exist
+ foreach ($packages as $pkg) {
+ if ($pkg['path'] === $input->getArgument('path')) {
+ $io->error([
+ sprintf('It appears that the path "%s" is currently being used.', $pkg['path']),
+ 'Please check your bard.json file',
+ ]);
+ return self::FAILURE;
+ }
+ }
$packages[] = [
- 'path' => $input->getArgument('path'),
+ 'path' => $input->getArgument('path'),
'repository' => $input->getArgument('repository'),
];
+ // ---
+
$bardConfig = $bardConfig->setSection('packages', $packages);
$commands = [
['git', 'subtree', 'add', '--prefix', $input->getArgument('path'), $input->getArgument('repository'), $input->getOption('branch'), '--squash'],
@@ -51,10 +74,15 @@ protected function execute(InputInterface $input, OutputInterface $output): int
foreach ($commands as $cmd) {
$process = new Process($cmd);
$io->text($process->getCommandLine());
- $this->getHelper('process')->mustRun($output, $process, sprintf('There was and error running command: %s', $process->getCommandLine()));
+ if (!$isDryRun) {
+ $this->getHelper('process')->mustRun($output, $process, sprintf('There was and error running command: %s', $process->getCommandLine()));
+ }
+ }
+
+ if (!$isDryRun) {
+ file_put_contents($bardConfig->getFilename(), $bardConfig->toJson());
}
- file_put_contents($bardConfig->getFilename(), $bardConfig->toJson());
$io->success('Package has been added.');
return self::SUCCESS;
diff --git a/src/SonsOfPHP/Bard/src/Console/Command/CopyCommand.php b/src/SonsOfPHP/Bard/src/Console/Command/CopyCommand.php
index 26f9d90d..c63df3dd 100644
--- a/src/SonsOfPHP/Bard/src/Console/Command/CopyCommand.php
+++ b/src/SonsOfPHP/Bard/src/Console/Command/CopyCommand.php
@@ -7,6 +7,7 @@
use SonsOfPHP\Bard\JsonFile;
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\Console\Style\SymfonyStyle;
use Symfony\Component\Process\Process;
@@ -22,25 +23,56 @@ protected function configure(): void
{
$this
->setDescription('Copies a file to each package')
+ ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Dry Run (Do not make any changes)')
->addArgument('source', InputArgument::REQUIRED, 'Source file to copy')
+ ->addArgument('package', InputArgument::OPTIONAL, 'Which package?')
+ ->setHelp(
+ <<<'HELP'
+The copy command will copy whatever file you give it to all the other
+repositories it is managing. This is useful for LICENSE files.
+
+Examples:
+
+ %command.full_name% LICENSE
+
+Read more at https://docs.sonsofphp.com/bard/
+HELP
+ )
;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
- $io = new SymfonyStyle($input, $output);
+ $io = new SymfonyStyle($input, $output);
+ $isDryRun = $input->getOption('dry-run');
+
+ // ---
$sourceFile = $input->getOption('working-dir') . '/' . $input->getArgument('source');
if (!is_file($sourceFile)) {
throw new \RuntimeException(sprintf('The file "%s" is an invalid file.', $sourceFile));
}
+ // ---
+
+ // ---
$bardJsonFile = new JsonFile($input->getOption('working-dir') . '/bard.json');
foreach ($bardJsonFile->getSection('packages') as $pkg) {
+ $pkgComposerFile = realpath($input->getOption('working-dir') . '/' . $pkg['path'] . '/composer.json');
+ $pkgComposerJsonFile = new JsonFile($pkgComposerFile);
+ $pkgName = $pkgComposerJsonFile->getSection('name');
+
+ if (null !== $input->getArgument('package') && $pkgName !== $input->getArgument('package')) {
+ continue;
+ }
+
$process = new Process(['cp', $sourceFile, $pkg['path']]);
$io->text($process->getCommandLine());
- $this->getHelper('process')->run($output, $process);
+ if (!$isDryRun) {
+ $this->getHelper('process')->run($output, $process);
+ }
}
+ // ---
- $io->success('File has been copied.');
+ $io->success(sprintf('File "%s" has been copied to all managed repos.', $sourceFile));
return self::SUCCESS;
}
diff --git a/src/SonsOfPHP/Bard/src/Console/Command/InitCommand.php b/src/SonsOfPHP/Bard/src/Console/Command/InitCommand.php
index 6ea7ffd3..0151fef4 100644
--- a/src/SonsOfPHP/Bard/src/Console/Command/InitCommand.php
+++ b/src/SonsOfPHP/Bard/src/Console/Command/InitCommand.php
@@ -7,6 +7,7 @@
use SonsOfPHP\Bard\JsonFile;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
/**
* Creates the initial bard.json file.
@@ -17,11 +18,6 @@ final class InitCommand extends AbstractCommand
{
protected static $defaultName = 'init';
- // public function __construct()
- // {
- // parent::__construct();
- // }
-
protected function configure(): void
{
$this
@@ -29,14 +25,13 @@ protected function configure(): void
;
}
- protected function initialize(InputInterface $input, OutputInterface $output): void {}
-
protected function execute(InputInterface $input, OutputInterface $output): int
{
+ $io = new SymfonyStyle($input, $output);
$filename = $input->getOption('working-dir') . '/bard.json';
if (file_exists($filename)) {
- $output->writeln('bard.json file already exists');
+ $io->error(sprintf('%s/bard.json file already exists', $input->getOption('working-dir')));
return self::FAILURE;
}
@@ -51,7 +46,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
['path' => 'packages/component', 'repository' => 'git@github.com/org/component'],
]);
- $output->writeln($bardJsonFile->toJson());
+ $io->text($bardJsonFile->toJson());
file_put_contents($bardJsonFile->getFilename(), $bardJsonFile->toJson());
diff --git a/src/SonsOfPHP/Bard/src/Console/Command/MergeCommand.php b/src/SonsOfPHP/Bard/src/Console/Command/MergeCommand.php
index 77de3595..67469bef 100644
--- a/src/SonsOfPHP/Bard/src/Console/Command/MergeCommand.php
+++ b/src/SonsOfPHP/Bard/src/Console/Command/MergeCommand.php
@@ -16,8 +16,11 @@
use SonsOfPHP\Bard\Worker\File\Composer\Root\UpdateRequireDevSection;
use SonsOfPHP\Bard\Worker\File\Composer\Root\UpdateRequireSection;
use SonsOfPHP\Component\Json\Json;
+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\Console\Style\SymfonyStyle;
/**
* Merges composer.json files.
@@ -42,8 +45,9 @@ public function __construct()
protected function configure(): void
{
$this
- // options for dry-run, by default it should be a dry-run
->setDescription('Merges package composer.json files into main composer.json file')
+ ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Dry Run (Do not make any changes)')
+ ->addArgument('package', InputArgument::OPTIONAL, 'Which package?')
;
}
@@ -66,6 +70,9 @@ protected function initialize(InputInterface $input, OutputInterface $output): v
protected function execute(InputInterface $input, OutputInterface $output): int
{
+ $io = new SymfonyStyle($input, $output);
+ $isDryRun = $input->getOption('dry-run');
+
$this->formatter = $this->getHelper('formatter');
$rootComposerJsonFile = new JsonFile($input->getOption('working-dir') . '/composer.json');
@@ -75,13 +82,17 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$rootComposerJsonFile = $rootComposerJsonFile->setSection('autoload-dev', []);
foreach ($this->bardConfig['packages'] as $pkg) {
- $packageComposerFile = realpath($input->getOption('working-dir') . '/' . $pkg['path'] . '/composer.json');
- if (!file_exists($packageComposerFile)) {
+ $pkgComposerFile = realpath($input->getOption('working-dir') . '/' . $pkg['path'] . '/composer.json');
+ if (!file_exists($pkgComposerFile)) {
$output->writeln(sprintf('No "%s" found, skipping', $packageComposerFile));
continue;
}
- $pkgComposerJsonFile = new JsonFile(realpath($input->getOption('working-dir') . '/' . $pkg['path'] . '/composer.json'));
+ $pkgComposerJsonFile = new JsonFile($pkgComposerFile);
+ $pkgName = $pkgComposerJsonFile->getSection('name');
+ if (null !== $input->getArgument('package') && $pkgName !== $input->getArgument('package')) {
+ continue;
+ }
$output->writeln($this->formatter->formatSection('bard', sprintf('Merging "%s" into root composer.json', $pkgComposerJsonFile->getSection('name'))));
@@ -100,12 +111,18 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$pkgComposerJsonFile = $pkgComposerJsonFile->with(new Authors($rootComposerJsonFile));
$pkgComposerJsonFile = $pkgComposerJsonFile->with(new Funding($rootComposerJsonFile));
- file_put_contents($pkgComposerJsonFile->getFilename(), $pkgComposerJsonFile->toJson());
+ if (!$isDryRun) {
+ file_put_contents($pkgComposerJsonFile->getFilename(), $pkgComposerJsonFile->toJson());
+ $io->text(sprintf('Updated "%s"', $pkgComposerJsonFile->getFilename()));
+ }
}
- file_put_contents($rootComposerJsonFile->getFilename(), $rootComposerJsonFile->toJson());
+ if (!$isDryRun) {
+ file_put_contents($rootComposerJsonFile->getFilename(), $rootComposerJsonFile->toJson());
+ $io->text(sprintf('Updated "%s"', $rootComposerJsonFile->getFilename()));
+ }
- $output->writeln('complete');
+ $io->success('Merge Complete');
return self::SUCCESS;
}
diff --git a/src/SonsOfPHP/Bard/src/Console/Command/PushCommand.php b/src/SonsOfPHP/Bard/src/Console/Command/PushCommand.php
index e0b03b0e..159e080f 100644
--- a/src/SonsOfPHP/Bard/src/Console/Command/PushCommand.php
+++ b/src/SonsOfPHP/Bard/src/Console/Command/PushCommand.php
@@ -5,6 +5,7 @@
namespace SonsOfPHP\Bard\Console\Command;
use SonsOfPHP\Bard\JsonFile;
+use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -25,32 +26,40 @@ protected function configure(): void
$this
->setDescription('Push changes to package repos using git subtree push')
->addOption('branch', null, InputOption::VALUE_REQUIRED, 'What branch we working with?', 'main')
+ ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Dry Run (Do not make any changes)')
+ ->addArgument('package', InputArgument::OPTIONAL, 'Which package do you want to push?')
;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$bardConfig = new JsonFile($input->getOption('working-dir') . '/bard.json');
- $formatter = $this->getHelper('formatter');
$io = new SymfonyStyle($input, $output);
+ $isDryRun = $input->getOption('dry-run');
foreach ($bardConfig->getSection('packages') as $pkg) {
$pkgComposerFile = realpath($input->getOption('working-dir') . '/' . $pkg['path'] . '/composer.json');
$pkgComposerJsonFile = new JsonFile($pkgComposerFile);
$pkgName = $pkgComposerJsonFile->getSection('name');
- $io->text(sprintf('Pushing %s>', $pkgName));
+
+ if (null !== $input->getArgument('package') && $pkgName !== $input->getArgument('package')) {
+ continue;
+ }
$commands = [
// subtree push
['git', 'subtree', 'push', '-P', $pkg['path'], $pkg['repository'], $input->getOption('branch')],
];
+ $io->text(sprintf('Pushing %s>', $pkgName));
foreach ($commands as $cmd) {
$process = new Process($cmd);
$io->text($process->getCommandLine());
- $this->getHelper('process')
- ->mustRun($output, $process, sprintf('There was and error running command: %s', $process->getCommandLine()))
- ->wait();
+ if (!$isDryRun) {
+ $this->getHelper('process')
+ ->mustRun($output, $process, sprintf('There was and error running command: %s', $process->getCommandLine()))
+ ->wait();
+ }
}
}
diff --git a/src/SonsOfPHP/Bard/src/Console/Command/ReleaseCommand.php b/src/SonsOfPHP/Bard/src/Console/Command/ReleaseCommand.php
index b2acf3e1..98af86fe 100644
--- a/src/SonsOfPHP/Bard/src/Console/Command/ReleaseCommand.php
+++ b/src/SonsOfPHP/Bard/src/Console/Command/ReleaseCommand.php
@@ -28,11 +28,6 @@ final class ReleaseCommand extends AbstractCommand
private $releaseVersion;
private bool $isDryRun = true;
- // public function __construct()
- // {
- // parent::__construct();
- // }
-
protected function configure(): void
{
$this
@@ -41,16 +36,16 @@ protected function configure(): void
->addOption('branch', null, InputOption::VALUE_REQUIRED, 'What branch we working with?', 'main')
->addArgument('release', InputArgument::REQUIRED, 'Next Release you want to start? Use format ..-+ or "major", "minor", "patch"')
->setHelp(
- <<%command.full_name%
+ %command.full_name%
- Read more at https://docs.SonsOfPHP.com
- EOT
+Read more at https://docs.SonsOfPHP.com
+EOT
);
}
@@ -87,8 +82,6 @@ protected function initialize(InputInterface $input, OutputInterface $output): v
$this->isDryRun = $input->getOption('dry-run');
}
- protected function interact(InputInterface $input, OutputInterface $output): void {}
-
protected function execute(InputInterface $input, OutputInterface $output): int
{
$formatter = $this->getHelper('formatter');
@@ -156,6 +149,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$io->success('Mother Repository Released');
// 4. Subtree Split for each package
+ // @todo run split command
$io->newLine();
$io->title(sprintf('updating package repos with release %s', $this->releaseVersion->toString()));
foreach ($this->bardConfig->getSection('packages') as $pkg) {
diff --git a/src/SonsOfPHP/Bard/src/Console/Command/SplitCommand.php b/src/SonsOfPHP/Bard/src/Console/Command/SplitCommand.php
index a941f4d6..94624f8a 100644
--- a/src/SonsOfPHP/Bard/src/Console/Command/SplitCommand.php
+++ b/src/SonsOfPHP/Bard/src/Console/Command/SplitCommand.php
@@ -5,6 +5,7 @@
namespace SonsOfPHP\Bard\Console\Command;
use SonsOfPHP\Bard\JsonFile;
+use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -23,20 +24,25 @@ protected function configure(): void
$this
->setDescription('Push changes to package repos using git subtree split')
->addOption('branch', null, InputOption::VALUE_REQUIRED, 'What branch we working with?', 'main')
+ ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Dry Run (Do not make any changes)')
+ ->addArgument('package', InputArgument::OPTIONAL, 'Which package do you want to push?')
;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$bardConfig = new JsonFile($input->getOption('working-dir') . '/bard.json');
- $formatter = $this->getHelper('formatter');
$io = new SymfonyStyle($input, $output);
+ $isDryRun = $input->getOption('dry-run');
foreach ($bardConfig->getSection('packages') as $pkg) {
$pkgComposerFile = realpath($input->getOption('working-dir') . '/' . $pkg['path'] . '/composer.json');
$pkgComposerJsonFile = new JsonFile($pkgComposerFile);
$pkgName = $pkgComposerJsonFile->getSection('name');
- $io->text(sprintf('Pushing %s>', $pkgName));
+
+ if (null !== $input->getArgument('package') && $pkgName !== $input->getArgument('package')) {
+ continue;
+ }
$commands = [
// subtree split
@@ -47,12 +53,15 @@ protected function execute(InputInterface $input, OutputInterface $output): int
['git', 'branch', '-D', $pkgName],
];
+ $io->text(sprintf('Pushing %s>', $pkgName));
foreach ($commands as $cmd) {
$process = new Process($cmd);
$io->text($process->getCommandLine());
- $this->getHelper('process')
- ->mustRun($output, $process, sprintf('There was and error running command: %s', $process->getCommandLine()))
- ->wait();
+ if (!$isDryRun) {
+ $this->getHelper('process')
+ ->mustRun($output, $process, sprintf('There was and error running command: %s', $process->getCommandLine()))
+ ->wait();
+ }
}
}
diff --git a/src/SonsOfPHP/Bard/src/Console/Command/UpdateCommand.php b/src/SonsOfPHP/Bard/src/Console/Command/UpdateCommand.php
index 4ebee170..c943f7fa 100644
--- a/src/SonsOfPHP/Bard/src/Console/Command/UpdateCommand.php
+++ b/src/SonsOfPHP/Bard/src/Console/Command/UpdateCommand.php
@@ -16,11 +16,6 @@ final class UpdateCommand extends AbstractCommand
{
protected static $defaultName = 'update';
- // public function __construct()
- // {
- // parent::__construct();
- // }
-
protected function configure(): void
{
$this
@@ -28,8 +23,6 @@ protected function configure(): void
;
}
- protected function initialize(InputInterface $input, OutputInterface $output): void {}
-
protected function execute(InputInterface $input, OutputInterface $output): int
{
$bardJsonFile = new JsonFile($input->getOption('working-dir') . '/bard.json');
diff --git a/src/SonsOfPHP/Bard/src/JsonFile.php b/src/SonsOfPHP/Bard/src/JsonFile.php
index b0d1a360..721d3359 100644
--- a/src/SonsOfPHP/Bard/src/JsonFile.php
+++ b/src/SonsOfPHP/Bard/src/JsonFile.php
@@ -7,17 +7,18 @@
use SonsOfPHP\Component\Json\Json;
/**
+ * Used to manage bard.json and composer.json files
+ *
* @author Joshua Estes
*/
final class JsonFile
{
- private string $filename;
private array $config = [];
private Json $json;
- public function __construct(string $filename)
- {
- $this->filename = $filename;
+ public function __construct(
+ private string $filename,
+ ) {
$this->json = new Json();
$this->load();
}
diff --git a/src/SonsOfPHP/Bard/src/Worker/File/Bard/UpdateVersion.php b/src/SonsOfPHP/Bard/src/Worker/File/Bard/UpdateVersion.php
index 529967db..b07fe17d 100644
--- a/src/SonsOfPHP/Bard/src/Worker/File/Bard/UpdateVersion.php
+++ b/src/SonsOfPHP/Bard/src/Worker/File/Bard/UpdateVersion.php
@@ -13,12 +13,7 @@
*/
final class UpdateVersion implements WorkerInterface
{
- private VersionInterface $version;
-
- public function __construct(VersionInterface $version)
- {
- $this->version = $version;
- }
+ public function __construct(private VersionInterface $version) {}
public function apply(JsonFile $bardJsonFile): JsonFile
{
diff --git a/src/SonsOfPHP/Bard/src/Worker/File/Composer/Root/UpdateRequireDevSection.php b/src/SonsOfPHP/Bard/src/Worker/File/Composer/Root/UpdateRequireDevSection.php
index 3b3976fe..74ee80d4 100644
--- a/src/SonsOfPHP/Bard/src/Worker/File/Composer/Root/UpdateRequireDevSection.php
+++ b/src/SonsOfPHP/Bard/src/Worker/File/Composer/Root/UpdateRequireDevSection.php
@@ -26,12 +26,33 @@ public function apply(JsonFile $rootComposerJsonFile): JsonFile
{
$rootRequireDev = $rootComposerJsonFile->getSection('require-dev');
$pkgRequireDev = $this->pkgComposerJsonFile->getSection('require-dev');
+ $rootRequire = $rootComposerJsonFile->getSection('require');
+ $rootReplace = $rootComposerJsonFile->getSection('replace');
+
if (null === $pkgRequireDev) {
return $rootComposerJsonFile;
}
foreach ($pkgRequireDev as $package => $version) {
+ if (array_key_exists($package, $rootRequire)) {
+ if (array_key_exists($package, $rootRequireDev)) {
+ unset($rootRequireDev[$package]);
+ }
+ continue;
+ }
+
+ if (array_key_exists($package, $rootReplace)) {
+ if (array_key_exists($package, $rootRequireDev)) {
+ unset($rootRequireDev[$package]);
+ }
+
+ if (array_key_exists($package, $rootRequire)) {
+ unset($rootRequire[$package]);
+ }
+ continue;
+ }
+
$rootRequireDev[$package] = $version;
}