From 2232593b450ce1143d870581a1ecb21589f521db Mon Sep 17 00:00:00 2001 From: Dane Powell Date: Thu, 12 Dec 2024 11:10:59 -0800 Subject: [PATCH] CLI-1396: [app:new:local] Add project template option (#1838) * CLI-1396: [app:new:local] Add project template option * kill mutant * kill mutant --- src/Command/App/NewCommand.php | 41 +++++++++++++++---- .../src/Commands/App/NewCommandTest.php | 35 +++++++++++++++- 2 files changed, 66 insertions(+), 10 deletions(-) diff --git a/src/Command/App/NewCommand.php b/src/Command/App/NewCommand.php index 46552d2d2..285ee9d0f 100644 --- a/src/Command/App/NewCommand.php +++ b/src/Command/App/NewCommand.php @@ -11,28 +11,42 @@ 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\Filesystem\Path; #[AsCommand(name: 'app:new:local', description: 'Create a new Drupal or Next.js project', aliases: ['new'])] final class NewCommand extends CommandBase { + /** + * @var string[] + */ + private static array $distros = [ + 'acquia_drupal_recommended' => 'acquia/drupal-recommended-project', + 'acquia_next_acms' => 'acquia/next-acms', + ]; protected function configure(): void { $this - ->addArgument('directory', InputArgument::OPTIONAL, 'The destination directory'); + ->addArgument('directory', InputArgument::OPTIONAL, 'The destination directory') + ->addOption('template', 't', InputOption::VALUE_OPTIONAL, 'The project template', null, array_keys(self::$distros)) + ->addUsage('-t acquia_drupal_recommended'); } + /** + * @throws \Acquia\Cli\Exception\AcquiaCliException + */ protected function execute(InputInterface $input, OutputInterface $output): int { $this->output->writeln('Acquia recommends most customers use acquia/drupal-recommended-project to setup a Drupal project, which includes useful utilities such as Acquia Connector.'); $this->output->writeln('acquia/next-acms is a starter template for building a headless site powered by Acquia CMS and Next.js.'); - $distros = [ - 'acquia_drupal_recommended' => 'acquia/drupal-recommended-project', - 'acquia_next_acms' => 'acquia/next-acms', - ]; - $project = $this->io->choice('Choose a starting project', array_values($distros), $distros['acquia_drupal_recommended']); - $project = array_search($project, $distros, true); + + if ($input->hasOption('template') && $input->getOption('template')) { + $project = $input->getOption('template'); + } else { + $project = $this->io->choice('Choose a starting project', array_values(self::$distros), self::$distros['acquia_drupal_recommended']); + $project = array_search($project, self::$distros, true); + } if ($input->hasArgument('directory') && $input->getArgument('directory')) { $dir = Path::canonicalize($input->getArgument('directory')); @@ -46,13 +60,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int $output->writeln('Creating project. This may take a few minutes.'); if ($project === 'acquia_next_acms') { - $successMessage = "New Next JS project created in $dir. 🎉"; + $successMessage = "New Next.js project created in $dir. 🎉"; $this->localMachineHelper->checkRequiredBinariesExist(['node']); $this->createNextJsProject($dir); } else { $successMessage = "New 💧 Drupal project created in $dir. 🎉"; $this->localMachineHelper->checkRequiredBinariesExist(['composer']); - $this->createDrupalProject($distros[$project], $dir); + $this->createDrupalProject(self::$distros[$project], $dir); } $this->initializeGitRepository($dir); @@ -63,6 +77,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int return Command::SUCCESS; } + /** + * @throws \Acquia\Cli\Exception\AcquiaCliException + */ private function createNextJsProject(string $dir): void { $process = $this->localMachineHelper->execute([ @@ -77,6 +94,9 @@ private function createNextJsProject(string $dir): void } } + /** + * @throws \Acquia\Cli\Exception\AcquiaCliException + */ private function createDrupalProject(string $project, string $dir): void { $process = $this->localMachineHelper->execute([ @@ -91,6 +111,9 @@ private function createDrupalProject(string $project, string $dir): void } } + /** + * @throws \Acquia\Cli\Exception\AcquiaCliException + */ private function initializeGitRepository(string $dir): void { if ( diff --git a/tests/phpunit/src/Commands/App/NewCommandTest.php b/tests/phpunit/src/Commands/App/NewCommandTest.php index ca7897141..41b371be0 100644 --- a/tests/phpunit/src/Commands/App/NewCommandTest.php +++ b/tests/phpunit/src/Commands/App/NewCommandTest.php @@ -136,7 +136,40 @@ public function testNewNextJSAppCommand(array $package, string $directory = 'nex $this->assertStringContainsString('Choose a starting project', $output); $this->assertStringContainsString($project, $output); $this->assertTrue($mockFileSystem->isAbsolutePath($this->newProjectDir), 'Directory path is not absolute'); - $this->assertStringContainsString('New Next JS project created in ' . $this->newProjectDir, $output); + $this->assertStringContainsString('New Next.js project created in ' . $this->newProjectDir, $output); + } + + public function testProjectTemplateOption(): void + { + $this->newProjectDir = Path::makeAbsolute('nextjs', $this->projectDir); + + $process = $this->prophet->prophesize(Process::class); + $process->isSuccessful()->willReturn(true); + $process->getExitCode()->willReturn(0); + + $localMachineHelper = $this->mockLocalMachineHelper(); + + $mockFileSystem = $this->mockGetFilesystem($localMachineHelper); + + $localMachineHelper->checkRequiredBinariesExist(["node"]) + ->shouldBeCalled(); + $this->mockExecuteNpxCreate($this->newProjectDir, $localMachineHelper, $process); + $localMachineHelper->checkRequiredBinariesExist(["git"]) + ->shouldBeCalled(); + $this->mockExecuteGitInit($localMachineHelper, $this->newProjectDir, $process); + $this->mockExecuteGitAdd($localMachineHelper, $this->newProjectDir, $process); + $this->mockExecuteGitCommit($localMachineHelper, $this->newProjectDir, $process); + + $this->executeCommand([ + '--template' => 'acquia_next_acms', + 'directory' => 'nextjs', + ]); + + $output = $this->getDisplay(); + $this->assertStringContainsString('Acquia recommends most customers use acquia/drupal-recommended-project to setup a Drupal project', $output); + $this->assertStringContainsString('acquia/next-acms', $output); + $this->assertTrue($mockFileSystem->isAbsolutePath($this->newProjectDir), 'Directory path is not absolute'); + $this->assertStringContainsString('New Next.js project created in ' . $this->newProjectDir, $output); } protected function mockExecuteComposerCreate(